使用recyclerView创建聊天活动

时间:2018-08-27 23:48:53

标签: java android android-recyclerview recycler-adapter

对于我的第一个非凡的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);
}

}

2 个答案:

答案 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的工作原理。