You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题分析与修复方案

问题根源

  1. 视图类型判断错误:getItemViewType方法中误用了message.getMessageId()和当前用户ID对比,正确的判断依据应该是message.getSenderId(),这会导致加载的布局和消息类型不匹配。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 01:12:02