title: Android: Multiple timers in a ListView with handler and runnable. 2 Problems
body: <p>I'm creating an app that contains a ListView with 2 columns. On the first column a countdown should be displayed and on the second column an additional text, that explains what is the countdown for.
  Below you see my code that works ... more or less.
  I have a listview with multiple rows an the timers are ticking.
  One problem is:
  the set.Text() in my runnable seems to override all rows. E.g. runnable for row 1 sets text also to row 2 and 3, runnable for row 2 sets text also for 1 and 3 and so on. This has the effect that the first column blinks (with correct values and values of other rows).
  How can I set text for a specific row in a listview?</p>
  
  <p>Next problem:
  the runnable is running on and on even if I remove callbacks from handler. But when the activity is in background or closed the timer ticking is not needed and I don't want to waste system resources.</p>
  
  <p>My Activity:</p>
  
  <pre><code>public class TimerActivity extends ListActivity {
  
  MyTimerAdapter myTimerAdapter = null;
  ArrayList&lt;Long&gt; timerList = new ArrayList&lt;Long&gt;();
  ArrayList&lt;String&gt; textList = new ArrayList&lt;String&gt;();
  
  @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();
  
      // some code to read database and fill 
      // array timerList with a long value (used for displaying a countdown) 
      // and textList with some additional text
  
      myTimerAdapter.add(timerList, textList);
      myTimerAdapter.notifyDataSetChanged();
  }
  
  }
  </code></pre>
  
  <p>My Adapter:</p>
  
  <pre><code>public class MyTimerAdapter extends ArrayAdapter&lt;String&gt; {
  private Activity mContext;
  private ArrayList&lt;Long&gt; mTimer;
  private ArrayList&lt;String&gt; mText;
  private int mViewId;
  private int mViewIdFieldTimer;
  private int mViewIdFieldText;
  private int listSize;
  private ArrayList&lt;Handler&gt; handlerList = new ArrayList&lt;Handler&gt;();
  private ArrayList&lt;TimerRunnable&gt; runList = new ArrayList&lt;TimerRunnable&gt;();
  
  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&lt;Long&gt; timer, ArrayList&lt;String&gt; text) {
      mTimer = timer;
      mText = text;
      listSize = mText.size();
      handlerList.clear();
      runList.clear();
  }
  
  @Override
  public void clear() {
      super.clear();
      int i;
      for (i=0; i&lt;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 to 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;
  }
  }
  </code></pre>
  
  <p>My Runnable:</p>
  
  <pre><code>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 &gt;= 0) {
  
              // some code formatting the time in seconds to something like hh:mm:ss (var String txt)
  
              tv.setText(txt);
  
              System.out.println(txt);  // only for tests; so I could see that runnable is still running
  
              mTimerHandler.postDelayed(this, 1000);
          } 
      }
  }
  
  public void stopHandler() {
      mTimerHandler.removeCallbacksAndMessages(null);
  }
  }
  </code></pre>