自定义 arrayAdapter 只返回 8 个对象
Custom arrayAdapter only returning 8 objects
我有一个包含 11 个对象的 ArrayList,当通过扩展自定义 ArrayAdapter 将其放入 Listview 时,它只显示 8 个对象,其中 9、10 和 11 与内容重复 1、2、3。
当我使用来自 SMS2PeopleAdapter class 的 int 位置调用 System.out.println("Position: " + position);
时,它只会显示位置为 10、9、8 ... 3 的 8 个项目。
你能帮我解决这个问题吗?
谢谢
Activity:
public class SMS2PeopleActivity extends AppCompatActivity {
ListView lv;
SMS2PeopleAdapter sms2PeopleAdapter;
ArrayList<SMS> listSMS2People;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sms2people);
lv = (ListView) findViewById(R.id.list_view_messages);
listSMS2People = new ArrayList<>();
listSMS2People.add(new SMS("1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"));
listSMS2People.add(new SMS("2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2"));
listSMS2People.add(new SMS("3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3"));
listSMS2People.add(new SMS("4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4"));
listSMS2People.add(new SMS("5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5"));
listSMS2People.add(new SMS("6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6"));
listSMS2People.add(new SMS("7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7"));
listSMS2People.add(new SMS("8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8"));
listSMS2People.add(new SMS("9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9"));
listSMS2People.add(new SMS("10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10"));
sms2PeopleAdapter = new SMS2PeopleAdapter(this, listSMS2People);
lv.setAdapter(sms2PeopleAdapter);
}
}
我的自定义 ArrayAdapter:
public class SMS2PeopleAdapter extends ArrayAdapter<SMS> {
Activity activity;
public SMS2PeopleAdapter(Activity activity, ArrayList<SMS> products) {
super(activity, 0, products);
this.activity = activity;
}
public View getView(int position, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
System.out.println("Position: " + position);
SMS sms = (SMS) getItem(position);
LayoutInflater inflater = activity.getLayoutInflater();
if (position % 2 == 0) {
convertView = inflater.inflate(R.layout.list_item_message_left, null);
TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);
txtMsg.setText(sms.getBody());
System.out.println(position + " Position: " + sms.getBody());
} else {
convertView = inflater.inflate(R.layout.list_item_message_right, null);
TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);
txtMsg.setText(sms.getBody());
System.out.println(position + " Position: " + sms.getBody());
}
}
return convertView;
}
}
在适配器的 getView 方法中,您需要处理 convertView 不为 null 的情况,我认为您只是 return 传递给它的视图。
您可能可以通过完全不检查 convertView 而每次 return 一个新视图来克服这个问题。这不是理想的,但会起作用。然后你可以查看 viewHolder 模式,或者查看新的 RecyclerView,它是一个新的变体,使它更容易。
实际情况是这样的。 getView()
是系统要求您提供要显示的视图,作为调用的一部分,它可能会为您提供不再显示的 "old" 视图。如果您愿意,您可以选择重新使用此视图,或者只是膨胀一个全新的视图,将其填充并 returning 。你正在做的是在系统没有给你旧视图时膨胀一个新视图,但如果它确实给你一个旧视图你只是 return 它而不用该特定行的新信息填充它,所以您只会看到这些行的旧视图。
如 nPn 所示,您只处理 convertView
参数为空的情况。这仅在尚未创建传递给您的适配器的视图时发生。一旦您开始滚动列表,Android 就会将滚动出屏幕的旧视图传递回您的适配器,以供在列表底部进入视图的 "new" 视图使用屏幕。通过仅使用填充屏幕所需的尽可能多的视图,最大限度地减少了资源。
所以您需要做的就是修改您的代码,以便它仅在 convertView
参数为 null 时从您的布局资源中扩充新视图。在那之后,它都是相同的代码。
实际上,现在我已经检查了您的代码,您似乎有两种不同的布局类型 - "left" 和 "right"。正确的做法是为您的列表实现两种不同的视图类型,并根据其位置将 getItemViewType()
覆盖为 return 正确的类型。
此外,由于您不知道传递的 convertView
是否是您需要的类型,最简单的做法就是每次都创建一个新视图。只要您没有庞大的列表并且整天来回滚动(每次新列表项出现在屏幕上时都会消耗更多资源),这就会起作用。如果这是一个问题,请按照 this SO post 了解如何在不创建新视图的情况下用另一个视图替换现有视图。
建议的修改如下所示。随意将 viewTypes 更改为枚举以获得更清晰的代码。
public View getView(int position, View convertView, ViewGroup viewGroup) {
System.out.println("Position: " + position);
SMS sms = (SMS) getItem(position);
int viewType = getItemViewType(position);
switch (viewType) {
case 1: { //LEFT
LayoutInflater inflater = activity.getLayoutInflater();
convertView = inflater.inflate(R.layout.list_item_message_left, null);
break;
}
case 2: { //RIGHT
LayoutInflater inflater = activity.getLayoutInflater();
convertView = inflater.inflate(R.layout.list_item_message_right, null);
break;
}
}
//Convert view is now garunteed to not be null, and to be of the correct type, so now just populate your data.
TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);
txtMsg.setText(sms.getBody());
System.out.println(position + " Position: " + sms.getBody());
return convertView;
}
@Override
public int getItemViewType(int position) {
if (position % 2 == 0)
return 1; //LEFT
else
return 2; //RIGHT
}
我有一个包含 11 个对象的 ArrayList,当通过扩展自定义 ArrayAdapter 将其放入 Listview 时,它只显示 8 个对象,其中 9、10 和 11 与内容重复 1、2、3。
当我使用来自 SMS2PeopleAdapter class 的 int 位置调用 System.out.println("Position: " + position);
时,它只会显示位置为 10、9、8 ... 3 的 8 个项目。
你能帮我解决这个问题吗? 谢谢
Activity:
public class SMS2PeopleActivity extends AppCompatActivity {
ListView lv;
SMS2PeopleAdapter sms2PeopleAdapter;
ArrayList<SMS> listSMS2People;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sms2people);
lv = (ListView) findViewById(R.id.list_view_messages);
listSMS2People = new ArrayList<>();
listSMS2People.add(new SMS("1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"));
listSMS2People.add(new SMS("2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2"));
listSMS2People.add(new SMS("3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3"));
listSMS2People.add(new SMS("4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4"));
listSMS2People.add(new SMS("5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5"));
listSMS2People.add(new SMS("6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6", "6"));
listSMS2People.add(new SMS("7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7", "7"));
listSMS2People.add(new SMS("8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", "8"));
listSMS2People.add(new SMS("9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9", "9"));
listSMS2People.add(new SMS("10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10"));
sms2PeopleAdapter = new SMS2PeopleAdapter(this, listSMS2People);
lv.setAdapter(sms2PeopleAdapter);
}
}
我的自定义 ArrayAdapter:
public class SMS2PeopleAdapter extends ArrayAdapter<SMS> {
Activity activity;
public SMS2PeopleAdapter(Activity activity, ArrayList<SMS> products) {
super(activity, 0, products);
this.activity = activity;
}
public View getView(int position, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
System.out.println("Position: " + position);
SMS sms = (SMS) getItem(position);
LayoutInflater inflater = activity.getLayoutInflater();
if (position % 2 == 0) {
convertView = inflater.inflate(R.layout.list_item_message_left, null);
TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);
txtMsg.setText(sms.getBody());
System.out.println(position + " Position: " + sms.getBody());
} else {
convertView = inflater.inflate(R.layout.list_item_message_right, null);
TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);
txtMsg.setText(sms.getBody());
System.out.println(position + " Position: " + sms.getBody());
}
}
return convertView;
}
}
在适配器的 getView 方法中,您需要处理 convertView 不为 null 的情况,我认为您只是 return 传递给它的视图。
您可能可以通过完全不检查 convertView 而每次 return 一个新视图来克服这个问题。这不是理想的,但会起作用。然后你可以查看 viewHolder 模式,或者查看新的 RecyclerView,它是一个新的变体,使它更容易。
实际情况是这样的。 getView()
是系统要求您提供要显示的视图,作为调用的一部分,它可能会为您提供不再显示的 "old" 视图。如果您愿意,您可以选择重新使用此视图,或者只是膨胀一个全新的视图,将其填充并 returning 。你正在做的是在系统没有给你旧视图时膨胀一个新视图,但如果它确实给你一个旧视图你只是 return 它而不用该特定行的新信息填充它,所以您只会看到这些行的旧视图。
如 nPn 所示,您只处理 convertView
参数为空的情况。这仅在尚未创建传递给您的适配器的视图时发生。一旦您开始滚动列表,Android 就会将滚动出屏幕的旧视图传递回您的适配器,以供在列表底部进入视图的 "new" 视图使用屏幕。通过仅使用填充屏幕所需的尽可能多的视图,最大限度地减少了资源。
所以您需要做的就是修改您的代码,以便它仅在 convertView
参数为 null 时从您的布局资源中扩充新视图。在那之后,它都是相同的代码。
实际上,现在我已经检查了您的代码,您似乎有两种不同的布局类型 - "left" 和 "right"。正确的做法是为您的列表实现两种不同的视图类型,并根据其位置将 getItemViewType()
覆盖为 return 正确的类型。
此外,由于您不知道传递的 convertView
是否是您需要的类型,最简单的做法就是每次都创建一个新视图。只要您没有庞大的列表并且整天来回滚动(每次新列表项出现在屏幕上时都会消耗更多资源),这就会起作用。如果这是一个问题,请按照 this SO post 了解如何在不创建新视图的情况下用另一个视图替换现有视图。
建议的修改如下所示。随意将 viewTypes 更改为枚举以获得更清晰的代码。
public View getView(int position, View convertView, ViewGroup viewGroup) {
System.out.println("Position: " + position);
SMS sms = (SMS) getItem(position);
int viewType = getItemViewType(position);
switch (viewType) {
case 1: { //LEFT
LayoutInflater inflater = activity.getLayoutInflater();
convertView = inflater.inflate(R.layout.list_item_message_left, null);
break;
}
case 2: { //RIGHT
LayoutInflater inflater = activity.getLayoutInflater();
convertView = inflater.inflate(R.layout.list_item_message_right, null);
break;
}
}
//Convert view is now garunteed to not be null, and to be of the correct type, so now just populate your data.
TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);
txtMsg.setText(sms.getBody());
System.out.println(position + " Position: " + sms.getBody());
return convertView;
}
@Override
public int getItemViewType(int position) {
if (position % 2 == 0)
return 1; //LEFT
else
return 2; //RIGHT
}