java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“void android.widget.TextView.setText(java.lang.CharSequence)”

问题描述 投票:0回答:1

我正在使用 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。

java android android-studio android-recyclerview
1个回答
0
投票

首先,如果您的数据是动态的并且可以更改,您应该使用 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 时,它将引用现有对象。

© www.soinside.com 2019 - 2024. All rights reserved.