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 »
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to