android - SeekBar and ListView recycling issue -
i using project in new app shows list of tracks play button , seekbar progress. able tracks playing got issue updating seekbar.
i use runnable , handler update seekbar. when hit play, seekbar of child view, moving correctly, child @ recycled position got updated too. example, have list of 10 items, 5 visible items only. when 1st track's seekbar got updating, 6th track updated. same thing happening 11th or 16th... positions if have bigger list. suggestion how updated properly?
this adapter
public class listviewadapter extends baseadapter { private activity activity; private list<ring> list; private layoutinflater inflater; private int mediafilelengthinmilliseconds; private final handler handler = new handler(); private mediaplayer player; private assetmanager assetmanager; public listviewadapter(activity activity, list<ring> list) { this.activity = activity; this.list = list; this.inflater = layoutinflater.from(this.activity); assetmanager = activity.getassets(); player = new mediaplayer(); } @override public int getcount() { return list.size(); } @override public ring getitem(int position) { return list.get(position); } @override public long getitemid(int position) { return position; } @override public view getview(final int position, view convertview, viewgroup parent) { final viewholder holder; if (convertview == null) { holder = new viewholder(); convertview = this.inflater.inflate(r.layout.list_view_item, parent, false); holder.play = (imagebutton) convertview.findviewbyid(r.id.play); holder.fav = (button) convertview.findviewbyid(r.id.fav); holder.set = (button) convertview.findviewbyid(r.id.setas); holder.title = (textview) convertview.findviewbyid(r.id.title); holder.seekbarprogress = (seekbar) convertview.findviewbyid(r.id.bar); holder.seekbarprogress.setmax(99); holder.seekbarprogress.setenabled(false); convertview.settag(holder); }else{ holder = (viewholder) convertview.gettag(); } holder.title.settext(list.get(position).getname()); holder.title.settypeface(typeface.createfromasset(activity.getassets(), "fonts/opensans-light.ttf")); holder.play.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { if (player.isplaying()) { player.pause(); holder.play.setimagedrawable(resourcescompat.getdrawable(activity.getresources(), android.r.drawable.ic_media_play, null)); holder.primaryseekbarprogressupdater(); } else { player.reset(); assetfiledescriptor afd = null; try { afd = assetmanager.openfd(list.get(position).getname() + ".mp3"); player.setdatasource(afd.getfiledescriptor(), afd.getstartoffset(), afd.getlength()); player.prepare(); player.start(); mediafilelengthinmilliseconds = player.getduration(); player.setonbufferingupdatelistener(new mediaplayer.onbufferingupdatelistener() { @override public void onbufferingupdate(mediaplayer mp, int percent) { holder.seekbarprogress.setsecondaryprogress(percent); } }); holder.seekbarprogress.setontouchlistener(new view.ontouchlistener() { @override public boolean ontouch(view v, motionevent event) { if (v.getid() == r.id.bar) { if (player.isplaying()) { seekbar sb = (seekbar) v; int playpositioninmillisecconds = (mediafilelengthinmilliseconds / 100) * sb.getprogress(); player.seekto(playpositioninmillisecconds); } } return true; } }); player.setoncompletionlistener(new mediaplayer.oncompletionlistener() { @override public void oncompletion(mediaplayer mp) { holder.play.setimagedrawable(resourcescompat.getdrawable(activity.getresources(), android.r.drawable.ic_media_play, null)); } }); holder.primaryseekbarprogressupdater(); holder.play.setimagedrawable(resourcescompat.getdrawable(activity.getresources(), android.r.drawable.ic_media_pause, null)); }catch (ioexception e) { e.printstacktrace(); } } } }); return convertview; } private class viewholder { textview title; imagebutton play; button set; button fav; seekbar seekbarprogress; void primaryseekbarprogressupdater() { seekbarprogress.setprogress((int) (((float) player.getcurrentposition() / mediafilelengthinmilliseconds) * 100)); // math construction give percentage of "was playing"/"song length" if (player.isplaying()) { runnable notification = new runnable() { public void run() { primaryseekbarprogressupdater(); } }; handler.postdelayed(notification,100); } } } }
as pointed out, list view items recycled. such, handler
should updating backing data model value of seekbar
, calling notifydatasetchanged()
on adapter. actual setting of seekbar
value should handled adapter's getview()
.
this not perfect fix because there lot of problems code, should address issue of multiple list items being updated.
- add
position
variable backing list model. - pass in position of item updating
primaryseekbarprogressupdater
- call
notifydatasetchanged()
- in
getview
, set seekbar position based on backing data model
void primaryseekbarprogressupdater(final int i) { list.get(i).setposition((int) (((float) player.getcurrentposition() / mediafilelengthinmilliseconds) * 100)); // math construction give percentage of "was playing"/"song length" notifydatasetchanged(); if (player.isplaying()) { runnable notification = new runnable() { public void run() { primaryseekbarprogressupdater(i); } }; handler.postdelayed(notification,100); } }
public view getview(final int position, view convertview, viewgroup parent) { ... holder.seekbarprogress.setprogress(list.get(position).getposition()); ... }
Comments
Post a Comment