我自己的 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;
}
}
}
我是 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;
}
}
}