android - Forcing a BaseAdapter to update it's views when AsyncTask is done -


ok, approach this. decoding locally stored encrypted , serialized objects in asynctask in activity. activity uses baseadapter (historyadapter) data display. asynctask shows progressdialog until decoding done. when onprogressupdate() first called, progressdialog cancelled. far, good. next, in onprogressupdate(), historyadapter notified of changes in common way, triggering it's getview() method. in historyadapter's getview(), second asynctask run modify created convertview , set data onto view.

here fails on me. inflate final layout in onprogressupdate(), , set properties , data on convertview fine here. changes don't show, though data set...

so, asynctask in historyadapter in in fact works perfectly, changes not visible. tried numurous suggestions mentioned on so, invalidating convertview, passing reference listview , using invalidateviews() (causes eternal loop no visible changes, makes sense).

i want this, because don't want load layout image placeholders before data available. got working, looks nasty , easy way out. need listview update (add item) when progress done. ideas?

edit: clarify: data set on adapter in right time. problem is, adapter creates blank view (placeholder) first (don't know other way, otherwise nullpointerexception in getview), view inflated / replaced view in onprogressupdate(). second view 1 should visible. works somewhat, because can , set properties on newly inflated view. changes not visible, , still seeing blank, created view. want update listview on each added item, not when items done loading...

public view getview(int position, view convertview, viewgroup parent) {     if (convertview == null) {           //convertview = minflater.inflate(r.layout.history_list_item_holo_dark, null);           convertview =  minflater.inflate(r.layout.blank, parent, false); // cheat: load blank/ empty layout         historyholder item  = history.get(position);         new asyncrequest(convertview, position).execute(item);     }            this.parent = parent;     return convertview; }//end method  static class viewholder {            textview title;     textview summary;     textview date;     imageview contact_icon;     imageview options_icon;     imageview type_icon; }//end class  private class asyncrequest extends asynctask<historyholder, view, view> {     viewholder holder           = null;     string title                = "";     string summary              = "";     string date                 = "";     long id                     = 0;     private view convertview    = null;     private string type         = "";     private int position        = -1;      public asyncrequest(view superview, int position){         this.convertview = superview;         this.position = position;     }//end constructor      @override     protected view doinbackground(historyholder... item) {         thread.currentthread().setname(getclass().getsimplename());           if (item[0].type.equals("log")){             //massive decrypting going on here 50-100 ms             //values title , summray set here         }         if (item[0].type.equals("sms")){             //massive decrypting going on here 50-100 ms             //values title , summray set here         }         publishprogress(convertview);         return convertview;     }// end method            @override     protected void onprogressupdate(view... view) {         super.onprogressupdate(view);     }// end method      @override     protected void onpostexecute(view result) {         super.onpostexecute(result);          if (!mathutils.iseven(position)){             result .setbackgroundcolor(context.getresources().getcolor(r.color.darker)); //this works expected, list items vary in color         } else {             result .setbackgroundcolor(context.getresources().getcolor(r.color.medium_dark));         } //this works expected, list items vary in color         result      = minflater.inflate(r.layout.history_list_item_holo_dark, parent, false);         result.settag(id);         holder                  = new viewholder();         holder.title            = (textview)    result .findviewbyid(r.id.title);         holder.summary          = (textview)    result .findviewbyid(r.id.summary);         holder.date             = (textview)    result .findviewbyid(r.id.date);         holder.contact_icon     = (imageview)   result .findviewbyid(r.id.icon);         holder.type_icon        = (imageview)   result .findviewbyid(r.id.type);         holder.options_icon     = (imageview)   result .findviewbyid(r.id.options);                  holder.options_icon.setfocusable(false);         holder.options_icon.settag(id);                   holder.title.settext(title); //this change doesnt show         holder.summary.settext(summary); //and on          result .settag(holder);     }//end method }//end inner class 

and know modify asyntask , don't need pass reference view in many places, again, it's code in progress. simplified example...

edit

okay, seems approach poor begin with, resulting in need have asynctask in historyadapter. adressed few issues resolve this.

  1. based on @delyan 's suggestion, decided load/ decrypt data before needed. using propertychangelistener this. implements onsharedpreferencechangelistener get's notified of changes data need. changes propagated interested listeners. data decrypted on application start , stored in global variable, accesible throughout application. see 'memory cache' referred to.
  2. based on comments , on accepted answer, decrypting done in background, there no longer need asynctasks.
  3. to further optimise performance of adapter, storing images needed listview in sparsearray, created , stored once. don't use hashmap this! furthermore, images created current view if aren't in hashmap (images aren't unique).

public class historyadapter extends baseadapter{          private static context context                  = applicationsubclass.getapplicationcontext_();      private contacts contacts                       = contacts.init(context);     private sparsearray<drawable> c_images          = new sparsearray<drawable>();     private hashmap<long, drawable> contact_imgs    = new hashmap<long, drawable>();     private arraylist<historyholder> history;     private layoutinflater minflater;      public historyadapter(context context) {         historyadapter.context = context;         minflater   = layoutinflater.from(context);     }//end constructor      ...      public view getview(int position, view convertview, viewgroup parent) {              final historyholder item = history.get(position);          drawable d = null;         if (c_images.get(position) == null){             if (!contact_imgs.containskey(item.contact_id)){                 if (item.in_contacts && item.contact_id != 0 && item.contact_id != -1){                      bitmap photo = contacts.getcontactphotothumbnailbycontactid(item.contact_id);                     if (photo != null){                         d = convert.bitmaptodrawable(context, photo, 128, 128);                     } else {                         d = context.getresources().getdrawable(r.drawable.ic_contact_picture);                 }                 } else {                     d = context.getresources().getdrawable(r.drawable.ic_contact_picture);                               }                 contact_imgs.put(item.contact_id, d);              }         }         c_images.put(position, contact_imgs.get(item.contact_id));          viewholder holder;         if (convertview == null) {             convertview             = minflater.inflate(r.layout.history_list_item_holo_dark, null);                         holder                  = new viewholder();             holder.position         = position;             holder.title            = (textview)    convertview.findviewbyid(r.id.title);             holder.summary          = (textview)    convertview.findviewbyid(r.id.summary);             holder.date             = (textview)    convertview.findviewbyid(r.id.date);             holder.contact_icon     = (imageview)   convertview.findviewbyid(r.id.icon);             holder.contact_icon.settag(position);             holder.options_icon     = (imageview)   convertview.findviewbyid(r.id.options);                      holder.options_icon.setfocusable(false);             holder.options_icon.settag(position);              convertview.settag(holder);          } else {             holder = (viewholder) convertview.gettag();         }          holder.contact_icon.setbackgrounddrawable(c_images.get(position));           holder.title.settext(item.title);         holder.summary.settext(item.summary);         holder.summary.setmaxlines(2);         holder.date.settext(item.date);             if (!mathutils.iseven(position)){             convertview.setbackgroundcolor(context.getresources().getcolor(r.color.darker));         } else {             convertview.setbackgroundcolor(context.getresources().getcolor(r.color.medium_dark));         }          return convertview;     }//end method      static class viewholder {                textview title;         textview summary;         textview date;         imageview contact_icon;         imageview options_icon;         int position;     }//end inner class }//end class 

dmmh, say, wanting (so need listview update (add item) when progress done) , doing (asynctask in getview) quite opposite things.

asynctask in end of getview used (however in different way) lazy image load i.e. show large images , show text+imageplaceholder until download complete.

you trying gradually fill in adapter's datasourse in first asynctask, every time, notify observers changes in dataset have cycle of getview calls every item in dataset. no good.

first, never, never!!! assume getview supply convertview, filled position. must either refill convert view new values, or turn off performance optimization , supply new view every time asked it. there's no way listview turn off recycling attempts because essence of listview, feature build upon.

second (resulted first), avoid @ means storing time-expensive (or user input) data newly created views only. views come , go, , not want walk long way expensive data (or lose user input). partial exclusion simple ineffective implementations of big image lazy loading. reduce memory usage download images visible user. more effective implementations use off-listview caching.

so, if want have items in listview added 1 @ time, in full glory, should:

0*. if have load user-provided icons , takes significant time load (i have not understand initial post that) make empty arraylist cache loaded ones , access them index. if images available index, ignore matter.

class decryptedrecord {     string title                = "";     string summary              = "";     string date                 = "";     int contactviewindex        = -1;     int contactoptionsindex     = -1;     int contactimageindex       = -1;     int typeimageindex          = -1;     int optionsimageindex       = -1; //if option icon varies. ignore otherwise } 
  1. declare decryptedrecord class, containing necessary data fill in view, e.g.:

  2. in asynctask: after loading every historyholder, perform "heavy decrypting" , fill new decryptedrecord values. if necessary load cusom image(see no.0*), load here , store index in cache(ignore if 0* irrelevant). attach filled decryptedrecord historyholder settag(). call publishprogress(historyholder)

  3. in onprogressupdate add historyholder adapter , call historyadapter.notifydatasetchanged();

  4. in getview() synchronously inflate view if convertview null, , in cases populate data decryptedrecord acqired historyholder.gettag(). inclusive, call setimagebitmap() on imageviews adressing necessary bitmap in corresponding list index.

this should want. please, if have errors/problems, try include complete code in question, or difficult understand details of situation. hope helps.


Comments

Popular posts from this blog

python - How to create a legend for 3D bar in matplotlib? -

java - Multi-Label Document Classification -

php - Dynamic url re-writing using htaccess -