【问题标题】:Custom arrayAdapter only returning 8 objects自定义 arrayAdapter 只返回 8 个对象
【发布时间】:2016-05-21 06:17:43
【问题描述】:

我有一个包含 11 个对象的 ArrayList,当通过扩展自定义 ArrayAdapter 将其放入 Listview 时,它只显示 8 个对象,从 9、10 和 11 与内容重复 1、2、3。

当我使用 SMS2PeopleAdapter 类中的 int 位置调用 System.out.println("Position: " + position); 时,它只会显示位置为 10、9、8、... 3 的 8 个项目。

你能帮我解决这个问题吗? 谢谢。

活动:

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;
    }
}

【问题讨论】:

    标签: android android-arrayadapter


    【解决方案1】:

    如 nPn 所示,您只处理convertView 参数为空的情况。这只发生在尚未创建传递给适配器的视图时。一旦您开始滚动列表,Android 就会将滚动离开屏幕的旧视图传回您的适配器,以用于在屏幕底部出现的“新”视图。这通过仅使用填满屏幕所需的尽可能多的视图来最大限度地减少资源。

    所以您需要做的就是修改您的代码,使其仅在convertView 参数为空时从您的布局资源中扩展一个新视图。之后,都是相同的代码。

    实际上,现在我已经检查了您的代码,您似乎有两种不同的布局类型 - “左”和“右”。正确的做法是为您的列表实现两种不同的视图类型,并覆盖 getItemViewType() 以根据其位置返回正确的类型。

    另外,由于您不知道传递的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
    }
    

    【讨论】:

      【解决方案2】:

      在适配器的 getView 方法中,您需要处理 convertView 不为空的情况,我认为您只是返回传递给它的视图。

      您可以通过根本不检查 convertView 并且每次只返回一个新视图来解决这个问题。这并不理想,但会起作用。然后你可以查看 viewHolder 模式,或者查看新的 RecyclerView,这是一个新的变体,它变得更加容易。

      实际发生的事情是这样的。 getView() 是系统要求您提供显示视图,作为调用的一部分,它可能会为您提供不再显示的“旧”视图。如果您愿意,您可以选择或重复使用此视图,或者只是扩充一个全新的视图,将其填充并返回。当系统没有给你一个旧视图时,你正在做的是膨胀一个新视图,但是如果它给你一个旧视图,你只需返回它而不用该特定行的新信息填充它,所以你只看到这些行的旧视图。

      【讨论】:

      • 是的,这正是正在发生的事情。 @Hoang:您的列表视图一次只能在屏幕上显示 8 个视图,对吧?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-16
      • 2012-10-10
      • 1970-01-01
      • 2014-10-10
      相关资源
      最近更新 更多