android - Image flickering while scrolling in RecyclerView -


i'm trying display list of songs found on device requesting data directly mediastore. i'm using recyclerview , adapter uses cursoradapter data mediastore. when adapter's onbindviewholder called, request passed bindview function of cursoradapter visual elements set.

public class listrecycleradapter3 extends recyclerview.adapter<listrecycleradapter3.songviewholder> {      // patch: because recyclerview.adapter in current form doesn't natively support     // cursors, "wrap" cursoradapter teh job     //     public mediastorehelper mediastorehelper;     customcursoradapter mcursoradapter;     context mcontext;       public class songviewholder extends recyclerview.viewholder {          public textview textitemtitle;         public textview textitemsub;         public imageview imgart;          public int position;         public string album_id;         public string path_art;         public string path_file;          public songviewholder(view v) {             super(v);             textitemtitle = (textview) v.findviewbyid(r.id.textitemtitle);             textitemsub = (textview) v.findviewbyid(r.id.textitemsub);             imgart = (imageview) v.findviewbyid(r.id.imgart);         }     }      private class customcursoradapter extends cursoradapter {          public customcursoradapter(context context, cursor c, int flags) {             super(context, c, flags);         }          @override         public view newview(final context context, cursor cursor, viewgroup parent) {              view v = layoutinflater.from(parent.getcontext())                     .inflate(r.layout.song_item, parent, false);              final songviewholder holder = new songviewholder(v);              v.settag(holder);              return v;         }          @override         public void bindview(view view, context context, cursor cursor) {             songviewholder holder = (songviewholder) view.gettag();              holder.position = cursor.getposition();              holder.textitemtitle.settext(cursor.getstring(cursor.getcolumnindex("title")));             holder.textitemsub.settext(cursor.getstring(cursor.getcolumnindex("artist")));              holder.album_id = cursor.getstring(cursor.getcolumnindex("album_id"));             holder.path_file = cursor.getstring(cursor.getcolumnindex("_data"));              picasso.with(holder.imgart.getcontext())                     .cancelrequest(holder.imgart);             holder.imgart.setimagedrawable(null);              new downloadimagetask(mediastorehelper, context, holder.imgart).execute(holder.album_id);         }      }      private class downloadimagetask extends asynctask<string, string, string> {          private mediastorehelper mediastorehelper;         private imageview imageview;         private context context;          public downloadimagetask(mediastorehelper mediastorehelper, context context, imageview imageview)         {             this.mediastorehelper = mediastorehelper;             this.context = context;             this.imageview = imageview;         }         @override         protected string doinbackground(string... ids) {             return mediastorehelper.getalbumartpath(ids[0]);         }          protected void onpostexecute(string result) {             picasso.with(context)                     .load(new file(result))                     .placeholder(r.drawable.ic_music)                     .fit()                     .into(imageview);         }     }      @override     public void onbindviewholder(songviewholder holder, int position) {         // passing binding operation cursor loader         mcursoradapter.getcursor().movetoposition(position);         mcursoradapter.bindview(holder.itemview, mcontext, mcursoradapter.getcursor());     }      @override     public songviewholder oncreateviewholder(viewgroup parent, int viewtype) {         // passing inflater job cursor-adapter         view v = mcursoradapter.newview(mcontext, mcursoradapter.getcursor(), parent);         return new songviewholder(v);     } } 

the problematic part image loading made of 2 parts:

  • with albumid got cursor, need use contentresolver album art file path
  • load image imageview using file path

these 2 passages need done in background otherwise scrolling become laggy. in bindview function called asynctask job, problem that, while scrolling fast, several image requests elaborated , result:

enter image description here

as can see code tried cancel pending picasso's requests on specific imageview, that's not enough. can problem fixed?

i solved adding field in viewholder containing asynctask relative item. in bindview function fisrt set asynctask.cancel(true) and, inside task made check iscancelled() before applying retrieved image using picasso.with(...).load(...). solved flickering.

bindview

if(holder.downloadimagetask != null)       holder.downloadimagetask.cancel(true);        holder.downloadimagetask = (downloadimagetask) new downloadimagetask(mediastorehelper, context, holder.imgart).execute(holder.album_id); 

asynctask

private class downloadimagetask extends asynctask<string, string, string> {          private mediastorehelper mediastorehelper;         private imageview imageview;         private context context;          public downloadimagetask(mediastorehelper mediastorehelper, context context, imageview imageview)         {             this.mediastorehelper = mediastorehelper;             this.context = context;             this.imageview = imageview;         }         @override         protected string doinbackground(string... ids) {             return mediastorehelper.getalbumartpath(ids[0]);         }          protected void onpostexecute(string result) {             if(!iscancelled())                 picasso.with(context)                         .load(new file(result))                         .placeholder(r.drawable.ic_music)                         .fit()                         .into(imageview);         }     } 

for sake of completeness, remove image recycled items , set placeholder.

@override public void onviewrecycled(songviewholder holder) {     super.onviewrecycled(holder);     picasso.with(holder.itemview.getcontext())             .cancelrequest(holder.imgart);     picasso.with(holder.itemview.getcontext())             .load(r.drawable.ic_music)             .fit()             .into(holder.imgart); } 

this solution made me think problem amount of time intercurring inside asynctask between image retrieval mediastore , time when image applied imageview picasso.


Comments

Popular posts from this blog

magento2 - Magento 2 admin grid add filter to collection -

Android volley - avoid multiple requests of the same kind to the server? -

Combining PHP Registration and Login into one class with multiple functions in one PHP file -