I'm trying to wrap my head around getView() and I don't think there's any topic in Android that creates more confusion and questions on StackOverflow and elsewhere. Everyone wants to know why it gets called so many times or in what order or not at all, but as Romain Guy says here , " there is absolutely no guarantee on the order in which getView() will be called nor how many times."
So I have a different question: I don't understand the convertView parameter.
I have a list of 15 items, 11 of which can fit on the screen. The very first time my app starts up getView() is called 48 times.
convertView is null for position 0 on the first call, the non-null for positions 1-11, then non-null for position 0 and null for positions 1-11, then null for position 0 and non-null for positions 1-11, and finally non-null for positions 0-11.
Could someone please explain why/when convertView is null versus non-null, how/why it starts off non-null for most positions, and why the same positions seem to bounce back and forth between these two states?
References to good tutorials, written in clear English, that explain convertView in detail would also be appreciated.
PS - my tests were done on a device running Android 2.3.5, if that matters. I know Google has changed ListActivity/adapter/getView stuff several times since then.
Per request, I'm including the Adapter code (I've obscured some proprietary names). Unfortunately I can't answer any "why did you do that?" questions, since I didn't write it
protected class PLxxxAdapter extends BaseAdapter {
public PLxxxAdapter(Context c) {
}
@Override
public int getCount() {
return listItems.size();
}
@Override
public Object getItem(int position) {
return listItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
boolean select;
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.PLxxxitem, null);
//This is still needed even though we point to an XML description
convertView.setLayoutParams(new ListView.LayoutParams(
ListView.LayoutParams.MATCH_PARENT,
ListView.LayoutParams.MATCH_PARENT));
holder = new ViewHolder();
//Get the views of the row
holder.itemView = (TextView)convertView.findViewById(R.id.post);
holder.cV1 = (CheckedTextView)convertView.findViewById(R.id.check1);
//Init the 'confirm' box listener
holder.cV1.setCompoundDrawablesWithIntrinsicBounds(0, R.layout.smallcb, 0, 0);
holder.cV1.setOnClickListener(new ConfBoxListener());
convertView.setTag(holder);
holder.cV1.setTag(holder); //These views need tags for onClick()
}
else {
holder = (ViewHolder)convertView.getTag(); // convertview NOT null
}
try {
int liSize = listItems.size();
if (position < liSize) {
holder.itemView.setText(listItems.get(position));
}
}
catch (Exception e) {
Log.e ("PLxxxActivity.getView Crash", "details " + e);
}
holder.cV1.setChecked(confirmed.get(position));
select = selected.get(position);
if (select == true) {
convertView.setBackgroundResource(R.color.colBlue);
}
else
convertView.setBackgroundResource(R.color.colGrey);
holder.position = position;
if (RemoteControlActivity.confCBs == true)
holder.cV1.setVisibility(View.VISIBLE);
else
holder.cV1.setVisibility(View.INVISIBLE);
return convertView;
} // end getView
} //end class PLxxxAdapter
convertView is the ListView Item Cache that is not visible, and hence it can be reused. It lets the ListView need not create a lot of ListItems, hence saving memeory and making the ListView more smooth.
getView. Get a View that displays the data at the specified position in the data set. You can either create a View manually or inflate it from an XML layout file. When the View is inflated, the parent View (GridView, ListView...) will apply default layout parameters unless you use LayoutInflater.
In this case what you can do is, create a empty layout in your main activity xml. Set a ID for that. While inflating the listview, inflate it to that layout.
An easy adapter to map columns from a cursor to TextViews or ImageViews defined in an XML file. Common base class of common implementation for an Adapter that can be used in both ListView (by implementing the specialized ListAdapter interface) and Spinner (by implementing the specialized SpinnerAdapter interface).
The first x
times, where x
is a number near the number of items visible on the screen, convertView
is null
. You need to instantiate a new View
to return.
When you scroll down, an existing View
is pushed upwards out of sight. Instead of destroying it, it can now be reused. You'll notice that, just before a new View
is pushed in from below, your getView
method is called, with a valid convertView
. This is exactly that View
that was pushed out of sight before (or maybe another one, there is some additional logic)!
Therefore, instead of re-instantiating your View
, which is costly, you can reuse the View
and adapt it to the new item
it represents. You will often see something like:
View view = convertView;
if(view == null){
view = LayoutInflater.from(getContext()).inflate(...);
}
// 'bind' view
return view;
The fact that your getView
method is called 48 times on startup, might actually be an issue with your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With