我正在使用 Android Studio 和 firebase 开发一个聊天应用程序,因此为了区分消息发送者和接收者,我尝试了以下代码:
消息适配器:
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.google.firebase.auth.FirebaseAuth;
import java.util.ArrayList;
import java.util.List;
import ma.enset.chatburst.ChatActivity;
import ma.enset.chatburst.R;
import ma.enset.chatburst.models.MessageModel;
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageViewHolder>{
private static final int VIEW_TYPE_SENT = 1;
private static final int VIEW_TYPE_RECEIVED = 2;
private Context context;
private List<MessageModel> messages;
public MessageAdapter(Context context) {
this.context = context;
this.messages = new ArrayList<>();
}
public void add(MessageModel message){
messages.add(message);
notifyDataSetChanged();
}
public void clear(){
messages.clear();
notifyDataSetChanged();
}
@NonNull
@Override
public MessageAdapter.MessageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if (viewType == VIEW_TYPE_SENT){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_row_sent, parent, false);
return new MessageAdapter.MessageViewHolder(view);
}
else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_row_received, parent, false);
return new MessageAdapter.MessageViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull MessageAdapter.MessageViewHolder holder, int position) {
MessageModel message = messages.get(position);
Log.i("info", "sender ID: " + message.getSenderId());
Log.i("info", "sender ID from Firebase: " + FirebaseAuth.getInstance().getUid());
Log.i("info", "message: " + message.getMessage());
Log.i("info", "Sent holder: " + holder.textViewSentMessage);
Log.i("info", "Received holder: " + holder.textViewReceivedMessage);
if (message.getSenderId().equals(FirebaseAuth.getInstance().getUid())){
holder.textViewSentMessage.setText(message.getMessage());
} else {
holder.textViewReceivedMessage.setText(message.getMessage());
}
}
@Override
public int getItemCount() {
return messages.size();
}
public List<MessageModel> getMessages() {
return messages;
}
@Override
public int getItemViewType(int position) {
if (messages.get(position).getMessageId().equals(FirebaseAuth.getInstance().getUid())){
return VIEW_TYPE_SENT;
} else {
return VIEW_TYPE_RECEIVED;
}
}
public static class MessageViewHolder extends RecyclerView.ViewHolder {
TextView textViewSentMessage, textViewReceivedMessage;
public MessageViewHolder(@NonNull View itemView) {
super(itemView);
textViewSentMessage = itemView.findViewById(R.id.sentMessage);
textViewReceivedMessage = itemView.findViewById(R.id.receivedMessage);
}
}
}
message_row_sent.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:layout_margin="10dp"
>
<TextView
android:id="@+id/sentMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/rounded_corner_sent"
android:textColor="@color/black"
android:padding="10dp"
android:textSize="16dp"
/>
</RelativeLayout>
</LinearLayout>
这里的问题是,每次我想发送消息时,它都会给我这个错误:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
我已经检查了TextView的id。
首先,如果您的数据是动态的并且可以更改,您应该使用 ListAdapter 而不是 RecyclerView.Adapter (这是所有适配器的基础)。
ListAdapter 允许您将数据源绑定到其适配器,同时在新数据准备好使用时运行 submitList。如果您需要根据位置或规格偏移项目,它允许您配置项目动画+装饰。
https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter
然后您可以分配一个比较器,它确定是否应将新数据添加到 RecyclerView 中。
class ExampleComparator :
DiffUtil.ItemCallback<MyViewModel>() {
override fun areItemsTheSame(
oldItem: MyViewModel,
newItem: MyViewModel
): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(
oldItem: MyViewModel,
newItem: MyViewModel
): Boolean {
return oldItem.uniqueId == newItem.uniqueId
}
}
其中 MyViewModel 表示 RecylerView 中单个项目的视图模型。
现在关于你的问题 该错误表明您尝试将 text data 绑定到的 TextView 为空。这意味着您正在尝试将数据绑定到尚未分配膨胀 TextView 的对象。
如果您没有使用 android DataBinding 库(https://developer.android.com/topic/libraries/data-binding),那么您需要确保在 onBindViewHolder 中添加空检查引用。
所以在你的情况下写下:
@Override
public void onBindViewHolder(@NonNull MessageAdapter.MessageViewHolder holder, int position) {
MessageModel message = messages.get(position);
Log.i("info", "sender ID: " + message.getSenderId());
Log.i("info", "sender ID from Firebase: " + FirebaseAuth.getInstance().getUid());
Log.i("info", "message: " + message.getMessage());
Log.i("info", "Sent holder: " + holder.textViewSentMessage);
Log.i("info", "Received holder: " + holder.textViewReceivedMessage);
if (message.getSenderId().equals(FirebaseAuth.getInstance().getUid())){
if(holder.textViewSentMessage != null){
holder.textViewSentMessage.setText(message.getMessage());
}
} else {
if(holder.textViewSentMessage != null){
holder.textViewReceivedMessage.setText(message.getMessage());
}
}
}
下次调用 onBindViewHolder 时,它将引用现有对象。