对于我的第一个非凡的Android应用,我正在制作一个涉及聊天室的应用。我正在使用聊天室活动来教我自己recyclerView,它没有像参考资料中过时的listView那样广泛介绍。我想我即将建立一个可正常使用的recyclerView和适配器,试图将listView的某些元素转换为recyclerView,但实际上很难使消息出现在recyclerView中。我究竟做错了什么?
这是我的聊天室活动:
public class ChatRoomActivity extends AppCompatActivity {
private static final String TAG = "Chat Room Activity";
private String mRoomID;
private String mRoomName;
private String mDisplayName;
private ArrayList<String> mUsernames = new ArrayList<>();
private ArrayList<String> mMessages = new ArrayList<>();
private RecyclerView mRecyclerView;
private EditText mInputText;
private ImageButton mSendButton;
private DatabaseReference mDatabaseReference;
private ChatRecyclerViewAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_room);
Log.d(TAG," onCreate: started.");
// identifies views
mInputText = findViewById(R.id.messageInput);
mSendButton = findViewById(R.id.sendButton);
//gets user display name from current user and gets Firebase reference
setupDisplayName();
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
// gets Google Place ID from shared preferences
SharedPreferences preferences = getSharedPreferences(PLACE_PREFS, 0);
mRoomID = preferences.getString(PLACE_ID_KEY, null);
mRoomName = preferences.getString(PLACE_NAME_KEY, null);
Toast.makeText(this, mRoomID + mRoomName, Toast.LENGTH_LONG).show();
// Creates listener to send the message when the "enter" button is pressed
mInputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
sendMessage();
return true;
}
});
// Adds an OnClickListener to the sendButton to send a message
mSendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessage();
}
});
}
private void setupDisplayName() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
mDisplayName = user.getDisplayName();
}
private void sendMessage() {
// Grabs the text the user typed in and pushes the message to Firebase
String input = mInputText.getText().toString();
if (!input.equals("")) {
Log.d(TAG, "Message sent");
Message chat = new Message(input, mDisplayName);
mDatabaseReference.child(mRoomID + "_messages").push().setValue(chat);
mInputText.setText("");
}
}
private void initRecyclerView(){
Log.d(TAG, "initRecyclerView: init recyclerview" );
mRecyclerView = findViewById(R.id.chatRecyclerView);
mAdapter = new ChatRecyclerViewAdapter(this,mMessages,mUsernames,mRoomID,mDatabaseReference);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
@Override
protected void onStart() {
super.onStart();
initRecyclerView();
}
@Override
protected void onStop() {
super.onStop();
mAdapter.cleanup();
}
}
这是我的适配器:
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
private static final String TAG = "ChatRecyclerViewAdapter";
private ArrayList<String> mMessage = new ArrayList<>();
private ArrayList<String> mAuthor = new ArrayList<>();
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
private ArrayList<DataSnapshot> mSnapshotList;
private ChildEventListener mListener = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
mSnapshotList.add(dataSnapshot);
notifyDataSetChanged();
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
};
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, DatabaseReference reference) {
this.mMessage = mMessage;
this.mAuthor = mAuthor;
this.mContext = mContext;
this.mRoomID = mRoomID;
mSnapshotList = new ArrayList<>();
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_msg_row,parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Log.d(TAG,"onBindViewHolder called");
holder.message.setText(mMessage.get(position));
holder.author.setText(mAuthor.get(position));
}
@Override
public int getItemCount() {
return mMessage.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView author;
TextView message;
RelativeLayout singleMessageContainer;
public ViewHolder(View itemView) {
super(itemView);
author = itemView.findViewById(R.id.chatAuthor);
message = itemView.findViewById(R.id.chatMessage);
singleMessageContainer = itemView.findViewById(R.id.singleMessageContainer);
}
}
void cleanup() {
mDatabaseReference.removeEventListener(mListener);
}
}
答案 0 :(得分:0)
看上面的代码,ChatRecyclerViewAdapter
的{{1}}方法返回消息数组(getItemCount()
)的大小。但是,在将项目添加到mMessage.size()
数组列表后,将调用notifyDataSetChanged()
。
您还必须将快照中的消息添加到message数组中,以便在调用DataSnapshot
时更新列表。
此外,出于性能原因,建议您避免一般调用notifyDataSetChanged()
。 RecyclerView.Adapter具有辅助方法,例如notifyDataSetChanged()
或notifyItemInserted
,用于向适配器通知列表中的新增内容。
答案 1 :(得分:0)
在RecyclerView适配器的onChildAdded()
中将记录插入ArrayList并在onBindViewHolder()
中检索记录的方式是完全错误的。
您为什么需要创建Firebase数据快照的ArrayList?请改用Message
类(您没有在问题中发布Message类的结构)。
像这样更改ChatRecyclerViewAdapter
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
// private ArrayList<String> mMessage = new ArrayList<>(); // comment or remove this line
// private ArrayList<String> mAuthor = new ArrayList<>(); // comment or remove this line
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
// private ArrayList<DataSnapshot> mSnapshotList; // comment or remove this line
private ArrayList<Message> messageList; // add this member
}
构造函数
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, DatabaseReference reference) {
// this.mMessage = mMessage; // comment or remove this line
// this.mAuthor = mAuthor; // comment or remove this line
this.mContext = mContext;
this.mRoomID = mRoomID;
messageList = new ArrayList<>(); // initialize messageList object
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
在onChildAdded()
方法内。
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
// convert Datasnapshot into a Message object
Message mes = dataSnapshot.getValue(Message.class);
// add it to an ArrayList of Message
messageList.add(mes); // notice the changes
notifyDataSetChanged();
}
内部onBindViewHolder()
方法
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// get single Message object from ArrayList
Message mes = messageList.get(position); // notice the difference
// just assuming that you've getter methods in your Message class
// please look into your code
holder.message.setText(mes.getMessage());
holder.author.setText(mes.getAuthor());
}
在getCount()
方法中
@Override
public int getItemCount() {
return messageList.size(); // return the size of the ArrayList
}
注意:使用Firebase和RecyclerView实施聊天的方式是完全错误的。您应该在Activity或Fragment中而不是在Adapter中使用/处理Firebase事件侦听器。
在进入Android高级知识之前,请先学习基本知识。您真的需要首先了解Firebase和RecyclerView的工作原理。