自定义 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
}