自定义arrayAdapter仅返回8个对象

时间:2016-02-10 18:18:55

标签: android android-arrayadapter

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

当我使用SMS2PeopleAdapter类中的int位置调用System.out.println("Position: " + position);时,它只显示8个位置为10,9,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;
    }
}

2 个答案:

答案 0 :(得分:1)

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

你可能完全没有检查convertView并且每次只返回一个新视图。这不是理想的,但可行。然后你可以查看viewHolder模式,或者查看新的RecyclerView,这是一个新的变体,使它更容易。

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

答案 1 :(得分:1)

正如nPn所示,您只处理convertView参数为空的情况。仅当尚未创建传递给适配器的视图时才会发生这种情况。一旦您开始滚动列表,Android就会将从屏幕滚动的旧视图传递回适配器,以用于&#34; new&#34;在屏幕底部进入视图的视图。通过仅使用填充屏幕所需的尽可能多的视图来最小化资源。

所以你需要做的就是修改代码,这样当convertView参数为null时,它只会从布局资源中膨胀一个新视图。在那之后,它们都是相同的代码。

实际上,既然我已经检查了您的代码,那么您似乎有两种不同的布局类型 - &#34;左&#34;和#34;权利&#34;。正确的方法是为列表实现两种不同的视图类型,并覆盖getItemViewType()以根据其位置返回正确的类型。

此外,由于您不知道传递的convertView是否属于您需要的类型,因此最简单的方法是每次都创建一个新视图。只要您没有庞大的列表并且整天都来回滚动(每次在屏幕上显示新的列表项时它将消耗更多资源),这将起作用。如果这是一个问题,请按照this SO post了解如何在不创建新视图的情况下将现有视图替换为另一个视图。

建议修改如下所示。您可以随意将viewTypes更改为enums,以获得更干净的代码。

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
}