My listView
seems to load correctly but on testing I think there's something wrong with it.
I'm looking at this tutorial : http://android.amberfog.com/?p=296#more-296
I've added the line:
System.out.println("getView " + position + " " + convertView);
Going by the tutorial, in logcat
I'm supposed to see convertView
values as I scroll down my listView
, like :
System.out(947): getView 20 android.widget.LinearLayout@437430f8
But in my logcat
all my convertViews
are null
. I don't even scroll the listView
and my 122 rows are immediately inflated - judging by logcat
. All the values are of the form:
System.out: getView number is :21convertView is : null
Am I doing something wrong?
Here's my code:
public class SelectPhoneContactAdapter extends BaseAdapter {
//define a list made out of SelectPhoneContacts and call it theContactsList
public List<SelectPhoneContact> theContactsList;
//define an array list made out of SelectContacts and call it arraylist
private ArrayList<SelectPhoneContact> arraylist;
Context _c;
//define a ViewHolder to hold our name and number info, instead of constantly querying
// findviewbyid. Makes the ListView run smoother
// ViewHolder viewHolder;
public SelectPhoneContactAdapter(final List<SelectPhoneContact> selectPhoneContacts, Context context) {
theContactsList = selectPhoneContacts;
_c = context;
this.arraylist = new ArrayList<SelectPhoneContact>();
this.arraylist.addAll(theContactsList);
}
@Override
public int getCount() {
System.out.println("the amount in arraylist :" + theContactsList.size());
return arraylist.size();
}
@Override
public Object getItem(int i) {
return theContactsList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
static class ViewHolder {
// In each cell in the listview show the items you want to have
// Having a ViewHolder caches our ids, instead of having to call and load each one again and again
TextView title, phone;
CheckBox check;
}
@Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
System.out.println("getView number is :" + i + "convertView is : " + convertView);
ViewHolder viewHolder = null;
if (convertView == null) {
//if there is nothing there (if it's null) inflate the view with the layout
LayoutInflater li = (LayoutInflater) _c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.phone_inflate_listview, null);
viewHolder = new ViewHolder();
// So, for example, title is cast to the name id, in phone_inflate_listview,
// phone is cast to the id called no etc
viewHolder.title = (TextView) convertView.findViewById(R.id.name);
viewHolder.phone = (TextView) convertView.findViewById(R.id.no);
viewHolder.check = (CheckBox) convertView.findViewById(R.id.checkBoxContact);
viewHolder.check.setVisibility(View.GONE);
//remember the state of the checkbox
viewHolder.check.setOnCheckedChangeListener((NewContact) _c);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
// store the holder with the view
final SelectPhoneContact data = (SelectPhoneContact) theContactsList.get(i);
//in the listview for contacts, set the name
viewHolder.title.setText(data.getName());
//in the listview for contacts, set the number
viewHolder.phone.setText(data.getPhone());
viewHolder.check.setChecked(data.isSelected());
viewHolder.check.setTag(data);
return convertView;
}
}
In my activity I use a function that measures the height of the listview before it loads on screen, perhaps this is part of the problem. Not sure it can be resolved or not, but if it can, that would be great.
From my NewContact.java:
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
adapter = new SelectPhoneContactAdapter(selectPhoneContacts, NewContact.this);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
justifyListViewHeightBasedOnChildren(listView);
}
justifyListViewHeightBasedOnChildren function :
//this is the function we call to measure the height of the listview
//we need this because there are problems with a listview within a scrollview
public static void justifyListViewHeightBasedOnChildren (ListView listView) {
ListAdapter adapter = listView.getAdapter();
if (adapter == null) {
return;
}
ViewGroup vg = listView;
int totalHeight = 0;
for (int i = 0; i < adapter.getCount(); i++) {
View listItem = adapter.getView(i, null, vg);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams par = listView.getLayoutParams();
par.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1));
listView.setLayoutParams(par);
listView.requestLayout();
System.out.println("the getcount is " + adapter.getCount());
System.out.println("the height is " + par.height);
}
When
ListView
calls thegetView()
method, whether or not theconvertView
parameter has a non-null value depends on whether or not theListView
is trying to "recycle" a view. Recycling happens when a view that was previously on screen got scrolled (far enough) off-screen that theListView
is confident it won't be needed for a while and can be re-used ("recycled") to display the values for a "new" view that is about to scroll on-screen.The idea here is that all of the children of the
ListView
have the same structure; they have the sameView
s in the same places. It's only the contents of those views that are changing. So rather than inflating yet another view, an old one that isn't in use any more can be recycled.Regardless of how it happens, if your
ListView
is large enough that it can hold all of its children at once, then recycling is impossible. You have essentially created a glorifiedLinearLayout
. Whether or not that is a problem is really up to you and your requirements. But when this happens, the whole "point" ofListView
(view recycling) won't happen.All of that is to say: seeing
null
for all 122 values ofconvertView
in all 122 calls togetView()
means that you are usingListView
differently than expected. If your app still runs perfectly, there's no strict need to change it. But know that you're not working within the expected boundaries of Google's framework.