Search code examples
androidlistviewconvertview

ConvertView being passed in as a view that's still on screen


In my custom ListAdapter, the first time that GetView() is called, convertView is passed in as NULL, but the second time it is passed in as the view that was created the first time. My ListView has 4 rows, and all 4 are on the screen at the same time. From the documentation, it seems that convertView should be a view that was already created and has now been scrolled off the screen. I expected convertView to be null all 4 times, so that it would create / inflate 4 separate views. Am I supposed to have a convertView after the first call to getView? Thanks.

In OnCreate():

    Cursor questions = db.loadQuestions(b.getLong("categoryId"), inputLanguage.getLanguageId(), outputLanguage.getLanguageId());
    startManagingCursor(questions);

    ListAdapter adapter = new QuestionsListAdapter(this, questions);

    ListView list = (ListView)findViewById(R.id.list1);
    setListAdapter(adapter);

Adapter class

private class QuestionsListAdapter extends BaseAdapter implements  ListAdapter{

    private Cursor c;
    private Context context;

    public QuestionsListAdapter(Context context, Cursor c) {
        this.c = c;
        this.context = context;
    }

    public Object getItem(int position) {
        c.moveToPosition(position);
        return new Question(c);
    }

    public long getItemId(int position) {
        c.moveToPosition(position);
        return new Question(c).get_id();
    }

    @Override
    public int getItemViewType(int position) {

        Question currentQuestion = (Question)this.getItem(position);
        if (currentQuestion.getType().equalsIgnoreCase("text"))
            return 0;
        else if (currentQuestion.getType().equalsIgnoreCase("range"))
            return 0;
        else if (currentQuestion.getType().equalsIgnoreCase("yesNo"))
            return 2;
        else if (currentQuestion.getType().equalsIgnoreCase("picker"))
            return 0;
        else if (currentQuestion.getType().equalsIgnoreCase("command"))
            return 0;
        else if (currentQuestion.getType().equalsIgnoreCase("datePicker"))
            return 0;
        else if (currentQuestion.getType().equalsIgnoreCase("diagram"))
            return 0;
        else
            return -1;
    }

    @Override
    public int getViewTypeCount() {
        return 7;
    }

    public int getCount() {
        return c.getCount();
    }

    public View getView(int position, View convertView, ViewGroup viewGroup) {

        Question currentQuestion = (Question)this.getItem(position);

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.question_row_text, null);
        }
        //setup cell

        return convertView;
    } 
}

Solution

  • If I remember right, GetView will be called twice for each row that's to be displayed. I think that the first set of calls is done for layout purposes, and the second set returns the views that will actually be displayed. It makes sense that the second set of calls should return the same Views that were returned in the first set of calls.

    In any case, your code should not care whether it's being called for layout or display. In almost all situations, if the convertView is non-null, then normally that convertView should be returned; otherwise, you should return a new View.