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

Reply via email to