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.
- based on @delyan 's suggestion, decided load/ decrypt data before needed. using
propertychangelistenerthis. implementsonsharedpreferencechangelistenerget'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. - based on comments , on accepted answer, decrypting done in background, there no longer need
asynctasks. - to further optimise performance of adapter, storing images needed
listviewinsparsearray, created , stored once. don't usehashmapthis! furthermore, images created currentviewif aren't inhashmap(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 } declare decryptedrecord class, containing necessary data fill in view, e.g.:
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)
in onprogressupdate add historyholder adapter , call historyadapter.notifydatasetchanged();
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
Post a Comment