Android: Multiple timers in a ListView with handler and runnable. 2 Problems -


i'm creating app contains listview 2 columns. on first column countdown should displayed , on second column additional text, explains countdown for. below see code works ... more or less. have listview multiple rows timers ticking. 1 problem is: set.text() in runnable seems override rows. e.g. runnable row 1 sets text row 2 , 3, runnable row 2 sets text 1 , 3 , on. has effect first column blinks (with correct values , values of other rows). how can set text specific row in listview?

next problem: runnable running on , on if remove callbacks handler. when activity in background or closed timer ticking not needed , don't want waste system resources.

my activity:

public class timeractivity extends listactivity {  mytimeradapter mytimeradapter = null; arraylist<long> timerlist = new arraylist<long>(); arraylist<string> textlist = new arraylist<string>();  @override public void oncreate(bundle savedinstancestate) {     super.oncreate(savedinstancestate);     setcontentview(r.layout.listactivity);      mytimeradapter = new mytimeradapter(this, r.layout.row, r.id.tv_timer, r.id.tv_text);     setlistadapter(mytimeradapter); }  @override protected void onresume() {     super.onresume();     refreshview(); }  @override protected void onpause() {     mytimeradapter.clear();     mytimeradapter.notifydatasetchanged();     super.onpause(); }  private void refreshview() {      mytimeradapter.clear();     timerlist.clear();     textlist.clear();      // code read database , fill      // array timerlist long value (used displaying countdown)      // , textlist additional text      mytimeradapter.add(timerlist, textlist);     mytimeradapter.notifydatasetchanged(); }  } 

my adapter:

public class mytimeradapter extends arrayadapter<string> { private activity mcontext; private arraylist<long> mtimer; private arraylist<string> mtext; private int mviewid; private int mviewidfieldtimer; private int mviewidfieldtext; private int listsize; private arraylist<handler> handlerlist = new arraylist<handler>(); private arraylist<timerrunnable> runlist = new arraylist<timerrunnable>();  public mytimeradapter(activity context, int textviewresid, int tv1, int tv2) {     super(context, textviewresid);     mcontext = context;     mviewid = textviewresid;     mviewidfieldtimer = tv1;     mviewidfieldtext = tv2;     listsize = 0; }  public void add(arraylist<long> timer, arraylist<string> text) {     mtimer = timer;     mtext = text;     listsize = mtext.size();     handlerlist.clear();     runlist.clear(); }  @override public void clear() {     super.clear();     int i;     (i=0; i<listsize; i++) {         handlerlist.get(i).removecallbacksandmessages(runlist.get(i));         runlist.get(i).stophandler();     } }  @override public int getcount() {     return listsize; }  @override public view getview(int position, view convertview, viewgroup parent) {     view v = convertview;     if (v == null) {         layoutinflater vi = mcontext.getlayoutinflater();         v = vi.inflate(mviewid, null);     }      long timerline = mtimer.get(position);     if (timerline != 0) {         textview tvtimer = (textview) v.findviewbyid(mviewidfieldtimer);          if (tvtimer != null) {             tvtimer.settag(position);             final handler mtimerhandler = new handler();             timerrunnable timertask = new timerrunnable(tvtimer, tvtimer.gettag().tostring(), timerline);             mtimerhandler.post(timertask);              // save in array stop later             handlerlist.add(mtimerhandler);             runlist.add(timertask);         }     }      string textline = mtext.get(position);     if (textline != null) {         textview tvtext = (textview) v.findviewbyid(mviewidfieldtext);         if (tvtext != null) {             tvtext.settext(textline);         }     }      return v; } } 

my runnable:

public class timerrunnable implements runnable { private textview tv; final handler mtimerhandler = new handler(); string tag; long endtime; long sec;  public timerrunnable (textview tv, string tag, long endtime) {     this.tv = tv;     this.tag = tag;     this.endtime = endtime; }  public void run() {     if (tv.gettag().tostring().equals(tag)) {         calendar cal = calendar.getinstance();         sec = endtime - (cal.gettimeinmillis() / 1000); //endtime - aktuelle zeit         if (sec >= 0) {              // code formatting time in seconds hh:mm:ss (var string txt)              tv.settext(txt);              system.out.println(txt);  // tests; see runnable still running              mtimerhandler.postdelayed(this, 1000);         }      } }  public void stophandler() {     mtimerhandler.removecallbacksandmessages(null); } } 

i follows:

  1. use timer (http://developer.android.com/reference/java/util/timer.html) , let run periodically every second or whatever.
  2. create timer object in activities oncreate() , cancel() timer in activities ondestroy() (or better start in onresume , cancel in onpause()). thats simplest way how avoid memory leaks , timer running if activity closed.
  3. update listview running timer. there 2 options:

    • simply call adapter.notifydatasetchanged() timer. lead "blinking" listview. try , checkout if work in application, since simplest implementation.
    • update directly textviews visible in listview

      private void updatetime(){  int firstvisibleitemindex = listview.getfirstvisibleposition();  (int = 0; < listview.getchildcount(); i++) {     view v = listview.getchildat(i);          youritem item = (youritem)adapter                 .getitem(firstvisibleitemindex + i));          viewholder vh = (viewholder) v.gettag();                             // calculate time somehow, i.e. call methot on data item                             vh.tvtimer.settext(item.getelapsedtime());       }  } 

      }

so guess second option best. may wonder viewholder is. viewholder pattern increases performance of listview. http://developer.android.com/training/improving-layouts/smooth-scrolling.html#viewholder problem of adapter is, findviewbyid() called everytime user scrolls. findviewbyid() expensive method call, since has traverse view childs find 1 given id. in simple adapter may not have impact (since have single child view, textview). viewholder should use in adapter implementation


Comments

Popular posts from this blog

java.util.scanner - How to read and add only numbers to array from a text file -

rewrite - Trouble with Wordpress multiple custom querystrings -