Your code in your getView implementation of the adapter looks good at
first sight. The structure of this method looks good.

I think there are a few issues though.

In your getView(...) method, you access the variable 'appList':

                        if (position >= appList.size()) {
                                return null;
                        }

and

                        ObjectToShow objectToShow = appList.get
(position);
                        ObjectToShow objectToShowWithMetadata =
appMap.get

The only place i can find a declared variable called 'appList' in your
example code is the one that is a private member of IconLoaderThread:

        class IconLoaderThread extends Thread {
                List<ObjectToShow> appList;
                ...
        }

In short, this 'appList' is accessed in two threads without any
synchronization or attempt to make it immutable.

Also, the plain assignment here worries me:
                public EfficientAdapter(Context c, List<ObjectToShow>
appList) {
                        if (appList != null) {
                                // Just refresh the list
                            --> appLocalList = appList; <---
                                ...
                        }
                        ...
                }

because in the method 'initList' you do something similar, but you
assign a copy of appList to appLocalList.

On Jun 30, 12:43 am, 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();
> > >                                - Hide quoted text -
>
> - Show quoted text -...
>
> 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