Firebase(Android):我的listView上没有显示图像,一旦我第一次将它上传到存储
Posted
技术标签:
【中文标题】Firebase(Android):我的listView上没有显示图像,一旦我第一次将它上传到存储【英文标题】:Firebase (Android): image not being displayed on my listView, once I first upload it to Storage 【发布时间】:2020-04-18 16:33:02 【问题描述】:我正在 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 在 onPause 时被清除)。当我旋转手机或重启应用程序时,会出现所有内容,包括上传的图像。当然,正如您所知,在用户上传图片后立即显示图片非常重要。
我做错了什么?或者我该怎么做才能在图像 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");
); */
MessageAdapter.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;
【问题讨论】:
【参考方案1】:与此同时,我想我找到了解决方案。
在我的 onSignedInInitialize 方法中,我曾声明如果 ChildEventListener 为空,那么我才会将 ChildEventListener 添加到数据库引用中。由于我在 onPause 上删除了此侦听器,并且当我返回 mainActivity(onActivityResult 上)时它可能不为空,我相信我没有将事件侦听器附加到数据库引用,因此之后没有显示任何内容正在上传的图片。
所以我删除了提到的条件,并在我回到 onResume 后立即将 ChildEventListener 实例添加到数据库引用中。它奏效了。
谢谢你,仍然! 最好的问候,
【讨论】:
尽管如此,请随时告诉我有哪些最佳实践。非常感谢;)以上是关于Firebase(Android):我的listView上没有显示图像,一旦我第一次将它上传到存储的主要内容,如果未能解决你的问题,请参考以下文章
firebase 社交登录不适用于我的 android 设备,仅适用于网络
我正在开发一个 Android 应用程序并使用 Firebase 作为我的后端