Android: getView() вызывается дважды в пользовательском адаптере

Я устанавливаю пользовательский SimpleCursorAdapter в ListView. По какой-то причине getView() FriendAdapter вызывается дважды для каждого элемента в БД. После некоторого расследования (у меня нет файла wrap_content в моем contact_list.xml), я до сих пор не могу понять, почему.

Какие могут быть причины? Кто-нибудь может помочь?

Спасибо

ContactSelection.java

public class ContactSelection extends ListActivity {

    private WhipemDBAdapter mDbHelper;  

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mDbHelper = new WhipemDBAdapter(this);
        mDbHelper.open();     

        setContentView(R.layout.contact_list);        

        Cursor c = mDbHelper.fetchAllFriends();
        startManagingCursor(c);     
        String[] from = new String[] {};
        int[] to = new int[] {};

        setListAdapter(new FriendAdapter(this, R.layout.contact_row, c, from, to));

        getListView().setItemsCanFocus(false);
        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mDbHelper.open();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mDbHelper.close();
    }
}

FriendAdapter.java

public class FriendAdapter extends SimpleCursorAdapter implements OnClickListener {

    private Context mContext;
    private int mLayout;
    private Cursor mCursor;
    private int mNameIndex;
    private int mIdIndex;
    private LayoutInflater mLayoutInflater; 
    private final ImageDownloader imageDownloader = new ImageDownloader();  

    private final class ViewHolder {
        public TextView name;
        public ImageView image;
        public CheckBox checkBox;
    }

    public FriendAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
        super(context, layout, c, from, to);

        this.mContext = context;
        this.mLayout = layout;
        this.mCursor = c;
        this.mNameIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_NAME);
        this.mIdIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_FB_ID);
        this.mLayoutInflater = LayoutInflater.from(context);        
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        if (mCursor.moveToPosition(position)) {
            ViewHolder viewHolder;

            if (convertView == null) {
                convertView = mLayoutInflater.inflate(mLayout, null);

                viewHolder = new ViewHolder();
                viewHolder.name = (TextView) convertView.findViewById(R.id.contact_name);
                viewHolder.image = (ImageView) convertView.findViewById(R.id.contact_pic);
                viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
                viewHolder.checkBox.setOnClickListener(this);

                convertView.setTag(viewHolder);
            }
            else {
                viewHolder = (ViewHolder) convertView.getTag();
            }

            String name = mCursor.getString(mNameIndex);
            String fb_id = mCursor.getString(mIdIndex);         
            boolean isChecked = ((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id);

            viewHolder.name.setText(name);
            imageDownloader.download("http://graph.facebook.com/"+fb_id+"/picture", viewHolder.image);

            viewHolder.checkBox.setTag(fb_id);
            viewHolder.checkBox.setChecked(isChecked);
        }

        return convertView;
    }

    @Override
    public void onClick(View v) {
        CheckBox cBox = (CheckBox) v;
        String fb_id = (String) cBox.getTag();

        if (cBox.isChecked()) {
            if (!((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id))
                ((GlobalVars) mContext.getApplicationContext()).addSelectedFriend(fb_id);
        } else {
            if (((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id))
                ((GlobalVars) mContext.getApplicationContext()).removeSelectedFriend(fb_id);
        }

    }
}

contact_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/contact_pic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/contact_name"        
        android:textSize="10sp"
        android:singleLine="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <CheckBox
        android:id="@+id/checkbox"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

список_контактов.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="horizontal"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
    <ListView
        android:id="@+id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
    <TextView
        android:id="@+id/android:empty"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="No items"/>
</LinearLayout>

person jul    schedule 08.03.2011    source источник


Ответы (4)


Это нормально и может произойти, если у вас есть список с height=wrap_content (среди прочего):

Посмотрите на последний пост: http://groups.google.com/group/android-developers/browse_thread/thread/4c4aedde22fe4594

person Peter Knego    schedule 08.03.2011
comment
В моем списке нет height=wrap_content. Должен ли я все еще не беспокоиться об этом? Получение/установка дважды всех значений в моей строке кажется бесполезной дублирующей обработкой. - person jul; 08.03.2011
comment
Как говорится в ссылке - это нормально, не беспокойтесь об этом. - person Peter Knego; 08.03.2011
comment
Да, это случилось и со мной. Вроде нормальное поведение. Однако иногда этого можно избежать, если вы запускаете свой код только в getView() на основе идентификатора позиции. Однако это немного хакерски. - person Michell Bak; 08.10.2011
comment
не беспокойтесь об этом. Ну, это вызвало у меня много нежелательного поведения, которое было трудно отладить. Рад, что нашел этот пост! - person user717572; 20.04.2012
comment
Я думаю, что мы должны беспокоиться, если адаптер является ресурсоемким. В моем случае это тоже проблема. - person Luis A. Florit; 05.10.2013
comment
@LuisA.Florit Согласен? Если не нужно каждый раз запрашивать значение или вычислять значение, зачем это делать? - person Zapnologica; 23.04.2015

Я использовал это. getView запускается дважды, но если вы проверите, является ли convertView null, код внутри будет запущен один раз.

public View getView(int position, View convertView, ViewGroup parent) {
    View superView = super.getView(position, convertView, parent);
    if (convertView == null)
    {
         // Customize superView here

    }
    return superView;
}
person user2064635    schedule 20.02.2013

Мне кажется, что представление создается дважды одним и тем же методом. Один в «if (convertView == null)», а другой «else». Если я ничего не делал в одном из операторов if, то он создается только один раз. Похоже, что сам метод вызывается только один раз.

person user5130224    schedule 21.03.2016

Чтобы получить вызов getView только один раз для каждой строки, вам нужно вызвать super.getView, а затем изменить возвращаемое представление. Это что-то вроде этого

public View getView(int position, View convertView, ViewGroup parent) {
    View superView = super.getView(position, convertView, parent);
    if (mCursor.moveToPosition(position)) {
         // Customize superView here

    }
    return superView;
}
person gmauri21    schedule 07.10.2011