java - Firebase(Android):我的listView上没有显示图像,一旦我第一次将它上传到存储
问题描述
我正在 Android 中实现一个即时消息应用程序(顺便说一下,FriendlyChat,Firebase Udacity 课程的一部分)。
它保存并显示每条消息的书面消息或图像。这些已保存项目的类称为 FriendlyMessage,其中包含消息的作者,然后是文本或图像。
我已经在 onAuthStateChanged 中设置了 ChildEventListener,它是在 onCreate 上编码的。话虽如此,AuthListener 仅在 onResume(将其附加/添加到 DatabaseReference)和 onPause(分离/删除)时调用。
发送按钮的 onClickListener 也在 onCreate 中设置。将 EditText 中的文本传递给 String,创建 FriendlyMessage 实例,然后使用 .push().setValue(object) 方法将其保存到数据库中。
每当我这样做时,都会调用 onChildAdded,在这里我可以将最新的 FriendlyMessage 实例添加到适配器,写入的消息会显示在 ListView 中。
对于图像,我有一个打开图像文件的按钮,然后我选择一个,然后被调用到 onActivityResult。
在这里,我可以检索图像,将其存储在 FirebaseStorage 中,甚至将其保存到数据库中(也可以使用 push().setValue(object) 方法)。
但是,在我编写的一些日志的帮助下,我注意到onChildAdded 没有被调用,因此,同时由于应用程序可能已暂停,我的 ListView 保持空白(ListView 在暂停)。当我旋转手机时,或者当我重新启动应用程序时,所有内容都会出现,包括上传的图像。但是,当然,如您所知,在用户上传图像后立即显示图像非常重要。
我究竟做错了什么?或者我该怎么做才能在图像 FriendlyMessage 实例保存到数据库时调用 onChildAdded(知道现在正在 onActivityResult 上调用它)?
MainActivity.java:
package com.google.firebase.udacity.friendlychat;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
import com.firebase.ui.auth.AuthUI;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
public static final String ANONYMOUS = "anonymous";
public static final int DEFAULT_MSG_LENGTH_LIMIT = 1000;
public static final int RC_SIGN_IN = 1;
public static final int RC_PHOTO_PICKER = 2;
private ListView mMessageListView;
private MessageAdapter mMessageAdapter;
private ProgressBar mProgressBar;
private ImageButton mPhotoPickerButton;
private EditText mMessageEditText;
private Button mSendButton;
private TextView mDisplayNameTextView;
private String mUsername;
private int countChildEventCalls; //for testing ChildEventListener calls
//Firebase variables
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference mDatabaseReference;
private FirebaseAuth mFirebaseAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private ChildEventListener mChildEventListener;
private FirebaseStorage mFirebaseStorage;
private StorageReference mChatPhotosStorageReference;
private List<AuthUI.IdpConfig> mAuthProviders = Arrays.asList(
new AuthUI.IdpConfig.EmailBuilder().build(),
new AuthUI.IdpConfig.GoogleBuilder().build());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mUsername = ANONYMOUS;
countChildEventCalls = 0;
mFirebaseDatabase = FirebaseDatabase.getInstance();
mFirebaseStorage = FirebaseStorage.getInstance();
mFirebaseAuth = FirebaseAuth.getInstance();
mDatabaseReference = mFirebaseDatabase.getReference().child("messages");
mChatPhotosStorageReference = mFirebaseStorage.getReference().child("chat_photos");
// Initialize references to views
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mMessageListView = (ListView) findViewById(R.id.messageListView);
mPhotoPickerButton = (ImageButton) findViewById(R.id.photoPickerButton);
mMessageEditText = (EditText) findViewById(R.id.messageEditText);
mSendButton = (Button) findViewById(R.id.sendButton);
mDisplayNameTextView = (TextView) findViewById(R.id.display_name);
// Initialize message ListView and its adapter
List<FriendlyMessage> friendlyMessages = new ArrayList<>();
mMessageAdapter = new MessageAdapter(this, R.layout.item_message, friendlyMessages);
mMessageListView.setAdapter(mMessageAdapter);
// Initialize progress bar
mProgressBar.setVisibility(ProgressBar.INVISIBLE);
// Enable Send button when there's text to send
mMessageEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().trim().length() > 0) {
mSendButton.setEnabled(true);
} else {
mSendButton.setEnabled(false);
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
mMessageEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(DEFAULT_MSG_LENGTH_LIMIT)});
// Send button sends a message and clears the EditText
mSendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// TODO: Send messages on click
FriendlyMessage friendlyMessage = new FriendlyMessage(mMessageEditText.getText().toString(), mUsername, null);
mDatabaseReference.push().setValue(friendlyMessage);
// Clear input box
mMessageEditText.setText("");
}
});
// ImagePickerButton shows an image picker to upload a image for a message
mPhotoPickerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
startActivityForResult(Intent.createChooser(intent, "Complete action using"), RC_PHOTO_PICKER);
}
});
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if(user != null) { //the user is logged in
onSignedInInitialize(user.getDisplayName());
}
else { //the user isn't logged in yet. Gotta launch FirebaseAuthUI
onSignedOutCleanup();
startActivityForResult(AuthUI.getInstance()
.createSignInIntentBuilder()
.setIsSmartLockEnabled(false)
.setAvailableProviders(mAuthProviders)
.build(),
RC_SIGN_IN);
}
}
};
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.sign_out_menu:
AuthUI.getInstance().signOut(this);
return true;
default: return super.onOptionsItemSelected(item);
}
}
@Override
protected void onResume(){
super.onResume();
mFirebaseAuth.addAuthStateListener(mAuthListener);
}
@Override
protected void onPause(){
super.onPause();
if(mAuthListener != null) {
mFirebaseAuth.removeAuthStateListener(mAuthListener);
}
detachDatabaseReadListener();
mMessageAdapter.clear();
}
public void onSignedInInitialize(String displayName){
mUsername = displayName;
mDisplayNameTextView.setText(mUsername);
if(mChildEventListener == null){
attachDatabaseReadListener();
}
}
public void attachDatabaseReadListener(){
mChildEventListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
countChildEventCalls++;
Log.v(TAG, "Could be Text or Photos: calling ChildEventListener");
FriendlyMessage message = dataSnapshot.getValue(FriendlyMessage.class);
mMessageAdapter.add(message);
Log.v(TAG, "Text or Photos: message added to Adapter. Calls: " + countChildEventCalls);
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
Log.v(TAG, "Text or Photos: calling onChildChange!");
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.v(TAG, "Text or Photos: onCancelled called.");
}
};
mDatabaseReference.addChildEventListener(mChildEventListener);
}
public void onSignedOutCleanup(){
mUsername = ANONYMOUS;
mMessageAdapter.clear();
detachDatabaseReadListener();
}
public void detachDatabaseReadListener(){
if(mChildEventListener != null){
mDatabaseReference.removeEventListener(mChildEventListener);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
Log.v(TAG, "Photos: Started activitiyForResult");
Log.v(TAG, "for Photos purpose, requestCode = " + requestCode + ", resultCode = " + resultCode);
if(requestCode == RC_SIGN_IN){
if(resultCode == RESULT_OK){
Toast.makeText(MainActivity.this, "You're logged in! Type with your friends", Toast.LENGTH_LONG).show();
}
else if (resultCode == RESULT_CANCELED){
Toast.makeText(MainActivity.this, "Sign-in cancelled", Toast.LENGTH_LONG).show();
finish();
}
}
else if (requestCode == RC_PHOTO_PICKER && resultCode == RESULT_OK) {
uploadImageToChat(data);
}
}
public void uploadImageToChat(Intent dataIntent){
Log.v(TAG, "Photos: Reached photo picker RC request");
Uri imageUri = dataIntent.getData();
final StorageReference photoRef = mChatPhotosStorageReference.child(imageUri.getLastPathSegment());
UploadTask uploadTask = photoRef.putFile(imageUri);
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
taskSnapshot.getStorage().getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri uri) {
String stringUrl = uri.toString();
Log.v(TAG, "Photos, uploaded, path: " + stringUrl);
FriendlyMessage imageMessage = new FriendlyMessage(null, mUsername, stringUrl);
mDatabaseReference.push().setValue(imageMessage);
Log.v(TAG, "Photos: Added Message to database");
}
});
}
});
//mMessageAdapter.notifyDataSetChanged();
/*
Task<Uri> taskUri = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
@Override
public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
}
// Continue with the task to get the download URL
return photoRef.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
@Override
public void onComplete(@NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Log.v(TAG, "Photos: upload successful");
Uri downloadUri = task.getResult();
String stringUrl = task.toString();
FriendlyMessage imageMessage = new FriendlyMessage(null, mUsername, stringUrl);
} else {
// Handle failures
// ...
Log.v(TAG, "Photos: wasn't able to upload photo");
}
}
}); */
}
}
消息适配器.java:
package com.google.firebase.udacity.friendlychat;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import java.util.List;
public class MessageAdapter extends ArrayAdapter<FriendlyMessage> {
public MessageAdapter(Context context, int resource, List<FriendlyMessage> objects) {
super(context, resource, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = ((Activity) getContext()).getLayoutInflater().inflate(R.layout.item_message, parent, false);
}
ImageView photoImageView = (ImageView) convertView.findViewById(R.id.photoImageView);
TextView messageTextView = (TextView) convertView.findViewById(R.id.messageTextView);
TextView authorTextView = (TextView) convertView.findViewById(R.id.nameTextView);
FriendlyMessage message = getItem(position);
boolean isPhoto = message.getPhotoUrl() != null;
if (isPhoto) {
messageTextView.setVisibility(View.GONE);
photoImageView.setVisibility(View.VISIBLE);
Glide.with(photoImageView.getContext())
.load(message.getPhotoUrl())
.into(photoImageView);
} else {
messageTextView.setVisibility(View.VISIBLE);
photoImageView.setVisibility(View.GONE);
messageTextView.setText(message.getText());
}
authorTextView.setText(message.getName());
return convertView;
}
}
解决方案
在此期间,我想我找到了解决方案。
在我的 onSignedInInitialize 方法中,我曾声明如果 ChildEventListener 为空,那么我才会将 ChildEventListener 添加到数据库引用中。由于我在 onPause 上删除了此侦听器,并且当我返回 mainActivity(onActivityResult 上)时它可能不为空,我相信我没有将事件侦听器附加到数据库引用,因此之后没有显示任何内容正在上传的图像。
因此,我删除了上述条件,并在我回到 onResume 后立即将 ChildEventListener 实例添加到数据库引用中。有效。
谢谢,还是!此致,
推荐阅读
- deserialization - 如何使用 Spring Cloud Stream 编写通用反序列化器?(Batch-Consumer)
- google-apps-script - 是否可以使用 Google Apps 脚本将文档另存为 epub?
- codenameone - 调查 Codename One iOS 应用程序上的 Java.Lang.NullPointerException
- android - 应用程序意外关闭 - Kotlin
- html - HTML 数据列表数组
- javascript - 如何在 ReactJS 中使用 clearInteval 让计时器自行清除?
- api - 如何在 asp.net core 和 javascript 中使用 API
- java - glassfish 4.1 类 org.springframework.beans.factory.BeanCreationException
- node.js - 纱线添加命令返回 http 405
- hyperledger-fabric - ERRO 001 无法运行对等体,因为无法初始化加密