我自己的 ArrayAdapter 中出现奇怪的 NullPointerException

Strange NullPointerException in my own ArrayAdapter

我是 Android Studio 编程的初学者,现在我正在通过蓝牙制作某种信使。所以我有自己的 ArrayAdapter class 它扩展了 ArrayAdapter class 并且它用于传出和传入消息。我希望传入消息位于左侧,传出消息位于右侧,因此我为此适配器制作了两种布局。我知道,在 Whosebug 上有很多解决方案可以使 ArrayAdapter 的每一行都具有很少的不同布局,但它们中的每一个都不起作用 - 更改布局会导致每一行的视图发生变化。所以我的解决方案是制作另一个布尔值 ArrayList,在 getView() 中我检查我在这个列表中的内容 - true 或 false - 并在 ArrayAdapter 中的该行上使用正确的布局(我正在通过 getView 的位置字段检查它( )).当我向第二个设备发送大量消息并尝试响应第一个设备时,会出现 NullPointerException (TextView)row.findViewById(R.id.singleIncomingMessage); 或者

(TextView)row.findViewById(R.id.singleOutgoingMessage);

这种异常似乎是随机出现的,但当然一定有规律可循。这是整个代码。怎么了?如果有一些拼写错误,我对我的语言感到抱歉;)

public class MyArrayAdapter extends ArrayAdapter<String> {
    public MyArrayAdapter(Context context, ArrayList<String> list) {
        super(context, 0, list);
        this.list =list;
        this.context=context;
    }

    ArrayList<String> list;
    Context context;

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public String getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public int getItemViewType(int position) {
        if(Messenger.inOut){
            return 1;
        }
        else{
            return 0;
        }
    }
    @Override
    public int getViewTypeCount() {
        return 2;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        int type=getItemViewType(position);
        View row=convertView;
        if(row==null){
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            if(Messenger.inOutList.get(position)==0){
                row=inflater.inflate(R.layout.outgoing_message_layout, parent, false);
            }
            if(Messenger.inOutList.get(position)==1){
                row=inflater.inflate(R.layout.incoming_message_layout, parent, false);
            }
        }
        String message=getItem(position);
        TextView label;
        if(Messenger.inOutList.get(position)==0){
            label=(TextView)row.findViewById(R.id.singleOutgoingMessage);
            label.setText(message);
        }
        if(Messenger.inOutList.get(position)==1){
            label=(TextView)row.findViewById(R.id.singleIncomingMessage);
            label.setText(message);
        }
        return row;
    }
}

我认为问题出在 row 非空的情况下。它可能以前被膨胀为传出消息布局,现在您正在回收它并试图将其视为传入消息布局,因此它找不到 TextView

很难确定这就是问题所在,因为我真的不知道 Messenger.* 调用在您的代码中的行为方式。由于您已经在 getView 中获得了 type,如果您保持这种方式,您应该使用它而不是 Messenger.inOutList.get(position)==X 来确定要使用哪个视图逻辑。 This question 对于如何始终如一地执行此操作有一些很好的答案。

另请记住,要使其正常工作,getItemViewType 必须始终 return 给定位置的相同类型,否则您必须检测到更改并在 [= 中扩充新布局14=]。如果 Messenger.inOut 不变,则没有理由使用这种格式(多布局格式)。如果它不是常量并且发生了变化,那么您需要在 getView

中检测到它

好的,非常感谢,我终于做到了。我使用了两个列表(布尔值和消息),在阅读了有关 ArrayAdapter 的信息后,我决定用这两个字段制作 class 并制作其对象的列表。该错误可能是因为第二个布尔值列表。如果有人有类似的问题,下面是我的最终代码。

public class MyArrayAdapter extends ArrayAdapter<MessageWithType> {
public MyArrayAdapter(Context context, ArrayList<MessageWithType> list) {
    super(context, 0, list);
    this.list =list;
    this.context=context;
}
public static final int TYPE_OUT = 0;
public static final int TYPE_IN = 1;

ArrayList<MessageWithType> list;
Context context;

@Override
public int getCount() {
    return list.size();
}

@Override
public MessageWithType getItem(int position) {
    return list.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}
@Override
public int getItemViewType(int position) {
    if(list.get(position).inOut){
        return 1;
    }
    else{
        return 0;
    }
}
@Override
public int getViewTypeCount() {
    return 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    MessageWithType item=getItem(position);
    int type=getItemViewType(position);
    View row=convertView;
    ViewHolder viewHolder=null;
    if(row==null){
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if(type==TYPE_OUT){
            row=inflater.inflate(R.layout.outgoing_message_layout, parent, false);
        }
        if(type==TYPE_IN){
            row=inflater.inflate(R.layout.incoming_message_layout, parent, false);
        }
        TextView label=(TextView)row.findViewById(R.id.singleMessage);
        viewHolder=new ViewHolder(label);
        row.setTag(viewHolder);
    }
    else{
        viewHolder=(ViewHolder)row.getTag();
    }
    viewHolder.textView.setText(item.message);

    return row;
}
public class ViewHolder{
    TextView textView;
    public ViewHolder(TextView textView){
        this.textView=textView;
    }
}

}