Android Studio+Firebase聊天应用发送消息触发NullPointerException
聊天应用消息区分功能空指针异常问题
我正在使用Android Studio和Firebase开发一款聊天应用,为区分消息发送方与接收方编写了相关代码,但每次尝试发送消息时都会抛出NullPointerException,已经检查过TextView的ID,问题仍未解决。
相关代码
MessageAdapter 代码
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
问题分析与修复方案
问题根源
- 视图类型判断错误:
getItemViewType方法中误用了message.getMessageId()和当前用户ID对比,正确的判断依据应该是message.getSenderId(),这会导致加载的布局和消息类型不匹配。 - ViewHolder跨布局查找控件:单个ViewHolder同时查找发送和接收布局的TextView,但每个布局只存在其中一个TextView,导致未加载的布局对应的TextView为null,调用
setText时触发空指针。
修复步骤
1. 修正视图类型判断逻辑
修改getItemViewType方法,用getSenderId替代getMessageId:
@Override public int getItemViewType(int position) { if (messages.get(position).getSenderId().equals(FirebaseAuth.getInstance().getUid())){ return VIEW_TYPE_SENT; } else { return VIEW_TYPE_RECEIVED; } }
2. 拆分ViewHolder类
为发送和接收消息分别创建ViewHolder,避免查找不存在的控件:
// 发送消息ViewHolder public static class SentMessageViewHolder extends RecyclerView.ViewHolder { TextView textViewSentMessage; public SentMessageViewHolder(@NonNull View itemView) { super(itemView); textViewSentMessage = itemView.findViewById(R.id.sentMessage); } } // 接收消息ViewHolder public static class ReceivedMessageViewHolder extends RecyclerView.ViewHolder { TextView textViewReceivedMessage; public ReceivedMessageViewHolder(@NonNull View itemView) { super(itemView); textViewReceivedMessage = itemView.findViewById(R.id.receivedMessage); } }
3. 更新onCreateViewHolder方法
根据视图类型返回对应的ViewHolder:
@NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_SENT){ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_row_sent, parent, false); return new SentMessageViewHolder(view); } else { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_row_received, parent, false); return new ReceivedMessageViewHolder(view); } }
4. 调整onBindViewHolder逻辑
根据视图类型强转ViewHolder并设置文本:
@Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { MessageModel message = messages.get(position); if (holder instanceof SentMessageViewHolder) { ((SentMessageViewHolder) holder).textViewSentMessage.setText(message.getMessage()); } else if (holder instanceof ReceivedMessageViewHolder) { ((ReceivedMessageViewHolder) holder).textViewReceivedMessage.setText(message.getMessage()); } }
5. 验证接收布局的ID一致性
确保message_row_received.xml中的TextView ID为@+id/receivedMessage,和接收ViewHolder中的查找ID一致。
内容的提问来源于stack exchange,提问作者wail_10
相关产品推荐
相关产品推荐

