Do not inflate a new view every time, not only is it less efficient but it can make your application run out of memory if the user scrolls for a while. It is a very poor way to work around whatever bug you have in your adapter.
On Mon, Jun 29, 2009 at 9:43 PM, Peter<[email protected]> wrote: > > Doug, you were right. > > If I inflate a new view each time instead of using the cached > convertView, the images never show incorrectly. This is obviously less > efficient, but it's right. I need to look more closely to see if I was > abusing the ViewHolder pattern, but I don't see how I was. > > This is what I'm doing now in convertView(): > > public View getView(int position, View convertView, ViewGroup > parent) > { > if (position >= appList.size()) { > return null; > } > convertView = mInflater.inflate > (R.layout.app_list_item, null); > > ObjectToShow objectToShow = appList.get > (position); > ObjectToShow objectToShowWithMetadata = > appMap.get > (objectToShow.getKey()); > if(objectToShow != null) { > if(objectToShowWithMetadata.getName() ! > = null) { > ((TextView) > convertView.findViewById(R.id.app_list_item_name)).setText > (objectToShowWithMetadata.getName()); > } > if(iconMap.get(objectToShow.getKey()) ! > = null) { > ((ImageView) > convertView.findViewByI(R.id.app_list_item_icon)).setImageBitmap > (iconMap.get(objectToShow.getKey())); > } > } else { > ((TextView)convertView.findViewById > (R.id.app_list_item_name)).setText(defaultText); > ((ImageView)convertView.findViewByI > (R.id.app_list_item_icon)).setImageDrawable(defaultIcon); > } > return convertView; > } > > Any thoughts? > > On Jun 27, 4:17 pm, Doug <[email protected]> wrote: >> Have you tried *not* caching the component views in your ViewHolder >> object - instead looking them up whenever you get a redraw request? >> You may find that the list is re-using objects, and your image issue >> is simply an artifact of that. >> >> Doug >> >> On Jun 26, 10:56 pm, Peter <[email protected]> wrote: >> >> >> >> > > There's not adefaultnumberof views created for an adapter. A list >> > > creates as many views as it needs to fill the screen. Views get reused >> > > only when you start scrolling or when the adapter send a >> > > notifyDatasetChanged(). You say you have a thread updating the data, >> > > what is exactly that thread doing? Please show code. >> >> > Here is some code. Perhaps it will help. >> >> > ********** the worker thread *************** >> > -------------------------------------- >> >> > class IconLoaderThread extends Thread { >> > List<ObjectToShow> appList; >> > void loadAllResources(List<ObjectToShow> appList) { >> > this.appList = appList; >> > start(); >> > } >> >> > public void run() { >> > int maxSize; >> >> > for (int i = 0; i < maxSize; i++) { >> > ObjectToShow appInfo = appList.get(i); >> > // network access occurs here >> > Bitmap icon = >> > appQuery.lookupAppIcon(appInfo); >> > Message msg = >> > handler.obtainMessage(MSG_REFRESH_APP_ICON); >> > Bundle data = new Bundle(); >> > data.putString("s3ObjectKey", >> > appInfo.getS3ObjectKey()); >> > msg.obj = icon; >> > msg.setData(data); >> > handler.sendMessage(msg); >> > } >> > Message doneMsg = >> > handler.obtainMessage(MSG_ICONS_DONE); >> > handler.sendMessage(doneMsg); >> > } >> > } >> >> > ********** the handler *************** >> > -------------------------------------- >> >> > private Handler handler = new Handler() { >> > public void handleMessage(Message msg) { >> > ObjectToShow appInfo; >> > switch (msg.what) { >> > case MSG_INIT_APP_LIST: >> > initProgressBar(); >> > >> > handler.sendEmptyMessage(MSG_NEXT_LOAD_STEP); >> > break; >> > case MSG_REFRESH_APP_ICON: >> > Bitmap icon = (Bitmap)msg.obj; >> > String s3ObjectKey = >> > msg.getData().getString("s3ObjectKey"); >> > if(icon == null || s3ObjectKey == null) { >> > Log.w(TAG, "Error loading icon"); >> > } else { >> > >> > efficientAdapter.updateAppInfoIcon(s3ObjectKey, icon); >> > } >> > break; >> > case MSG_REFRESH_APP_METADATA: >> > appInfo = (ObjectToShow)msg.obj; >> > if(appInfo == null) { >> > Log.w(TAG, "Error loading icon"); >> > } else { >> > >> > efficientAdapter.updateAppInfoMetadata(appInfo); >> > } >> > break; >> > case MSG_METADATA_DONE: >> > metadataLoaded = true; >> > >> > handler.sendEmptyMessage(MSG_NEXT_LOAD_STEP); >> > break; >> > case MSG_ICONS_DONE: >> > iconsLoaded = true; >> > >> > handler.sendEmptyMessage(MSG_NEXT_LOAD_STEP); >> > break; >> > case MSG_NEXT_LOAD_STEP: >> > if (metadataLoaded && iconsLoaded) { >> > doneLoadingMetadata(); >> > } >> > else if (metadataLoaded || iconsLoaded) { >> > if (firstRun) { >> > // Set the adapter here. >> > firstRun = false; >> > >> > appListView.setAdapter(efficientAdapter); >> > dismissLoadingMessage(); >> > } >> > initIconThread(); >> > } >> > else { >> > initMetadataThread(); >> > } >> > break; >> > default: >> > break; >> > } >> > } >> > }; >> >> > ********** the adapter *************** >> > -------------------------------------- >> >> > class EfficientAdapter extends BaseAdapter { >> > private List<ObjectToShow> appLocalList; >> > // IndexedObjectToShow just adds the int positions >> > associated with >> > the item in the ListView >> > private Map<String, IndexedObjectToShow> appLocalMap; >> > private Map<String, Bitmap> iconMap = >> > Collections.synchronizedMap >> > (new HashMap<String, Bitmap>()); >> > AppInfoComparator appInfoComparator = new >> > AppInfoComparator(); >> >> > public void initList(List<ObjectToShow> appList) { >> > if (appList != null) { >> > appLocalList = >> > Collections.synchronizedList(appList); >> >> > Collections.sort(appLocalList, >> > appInfoComparator); >> >> > appLocalMap = new TreeMap<String, >> > IndexedObjectToShow>(); >> > Iterator<ObjectToShow> iter = >> > appLocalList.iterator(); >> > int i = 0; >> > while (iter.hasNext()) { >> > ObjectToShow thisInfo = >> > iter.next(); >> > >> > appLocalMap.put(thisInfo.getS3ObjectKey(), new IndexedObjectToShow >> > (i, thisInfo)); >> > i++; >> > } >> > appLocalMap = >> > Collections.synchronizedMap(appLocalMap); >> > } >> > } >> >> > public long getItemId(int position) { >> > int maxSize = appLocalList.size(); >> > if( (position < 0) || (position >= maxSize)) { >> > Log.w(TAG, "Position out of bounds in List >> > Adapter"); >> > return -1; >> > } >> > return >> > appLocalMap.get(appLocalList.get(position).getS3ObjectKey >> > ()).index; >> > } >> >> > public EfficientAdapter(Context c, List<ObjectToShow> >> > appList) { >> > if (appList != null) { >> > // Just refresh the list >> > appLocalList = appList; >> >> > Collections.sort(appLocalList, >> > appInfoComparator); >> >> > appLocalMap = new TreeMap<String, >> > IndexedObjectToShow>(); >> > Iterator<ObjectToShow> iter = >> > appLocalList.iterator(); >> > int i = 0; >> > while (iter.hasNext()) { >> > ObjectToShow thisInfo = >> > iter.next(); >> > >> > appLocalMap.put(thisInfo.getS3ObjectKey(), new IndexedObjectToShow >> > (i, thisInfo)); >> > i++; >> > } >> > } >> > } >> >> > public int getCount() { >> > return appLocalList.size();... >> >> read more » > > > -- Romain Guy Android framework engineer [email protected] Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public forums, where I and others can see and answer them --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/android-developers?hl=en -~----------~----~----~----~------~----~------~--~---

