4

I have a issue with using a timer on a listview. In the list item I showed using sqlite values. There is a textview which showing time difference of last updated time of the data and current time. i have to show it in every one second. so the user can know how long he updated the record.

I tried this in several ways.

First way

I tried to add timer in adapter class. so for every item new timer is created. so application crashed because of many timers run simultaneously.

Second way

I tried using adapter.notifyDataSetChanged() way. Like as this.

Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
    @Override
    public void run() { 
        if (adapterChatThread != null) {
            adapter.notifyDataSetChanged();
        }
        timerHandler.postDelayed(this, 1000); // run every second
    }
};
timerRunnable.run();

I move to another activity when click on list item and user can come back to this Activity.

so in Onresume I used

timerHandler.postDelayed(timerRunnable, 500);

and OnPause

timerHandler.removeCallbacks(timerRunnable);

Issue is data is not showing well. I mean in every second data difference is not one second. some time differnce is 2sec, 5 sec, .. etc.

means timer is not working as I expected.

Third way

I used a asynctask and call it in every second using a timer.

class ThreadTimer extends AsyncTask<Void, Void, Void> {
    @Override
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        if (adapter != null)
            adapter.notifyDataSetChanged();
        super.onPostExecute(result);
    }
    }

I called this as in here

Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
    @Override
    public void run() { 
        new ThreadTimer().execute();
        timerHandler.postDelayed(this, 1000); // run every second
    }
};
timerRunnable.run();

previous issue triggered. (data not showing well)

Fourth way

Using AsyncTask as this

class ThreadTimer extends AsyncTask<Void, Void, Void> {
    void Sleep(int ms) {
        try {
            Thread.sleep(ms);
        } catch (Exception e) {
        }
    }

    @Override
    protected Void doInBackground(Void... params) {
        while (threadRun) {
            Sleep(1000);
            return null;
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        adapter.notifyDataSetChanged();
        super.onPostExecute(result);
    }
}

I called this class in OnResume. In on pause I set threadRun= false;

issue is same.

please help me.

My requirement is update list item in every second.

Thank you.

edit

here is my adapter class textview update code.

Date lastUpdatedTime;
final ChatThreadDAO ctd = new ChatThreadDAO();
long timeForNextResponse = ctd.getLastRespondedTime(vct.get(position).getThread_id());

try {
    if (vct.get(position).getThread_read_status() == 1 && timeForNextResponse > 0) {
        final long respTime = timeForNextResponse;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        lastUpdatedTime = formatter.parse(vct.get(position).getLast_updated_time());
        final long timeDiff = (new Date()).getTime() - lastUpdatedTime.getTime();
        if (timeDiff <= respTime) {
            timeForNextResponse = respTime - timeDiff;
            ctd.updateTimeRespondToLastMsg(vct.get(position).getThread_id(), timeForNextResponse);
            holder.tvChatTimer.setVisibility(View.VISIBLE);
            holder.tvChatTimer.setText(timeForNextResponse / 1000 + "");
        } else {
            ctd.updateTimeRespondToLastMsg(vct.get(position).getThread_id(), 0);
        }
    } else {
        holder.tvChatTimer.setVisibility(View.INVISIBLE);
    }
} catch (ParseException e) {
    e.printStackTrace();
}

here vct is

Vector vct;

I assign the values to vector in adapter class constructer.

Thushara
  • 559
  • 7
  • 22
  • Wait, are you changing the data in your adapter? – Barışcan Kayaoğlu Mar 18 '14 at 12:12
  • 1
    lastUpdatedTime must be set outside of your adapter, adapter is for handling your each row, so even it might work, you would still set your lastUpdatedTime each time you create or modify a row of your list view. lastUpdatedTime must be set whenever you change the contents of your vector, or notifying your adapter to refresh. – Barışcan Kayaoğlu Mar 18 '14 at 12:16
  • Thnak you so much. I removed update the lastUpdatedTime in adapter class and it works now fine. Thanks alot. – Thushara Mar 18 '14 at 12:49
  • it worked when I an not scroll it. but when scroll the list it shows incorrect values. is there any other way to implement this? – Thushara Mar 20 '14 at 12:22
  • Well I can't tell with your current code, but keep in mind that your rows are created/modified on GetView() method. So you need to make some modifications there, or your data might be incorrect in your array. You can check if your array contains the correct values. Default custom adapter creates a row each time you scroll according to your array, but most of the time you modify it so it re uses itself. But either way your get view will called. – Barışcan Kayaoğlu Mar 20 '14 at 14:01

1 Answers1

0

Here is an example similar to your case.

private class connectionControl extends Thread {
        boolean stop_ = false;

        public void stop_() {
            this.stop_ = true;
        }

        public void run() {
            System.out.println("Thread started:" + getClass().getSimpleName());
            while(!this.stop_) {
                try {
                    Thread.sleep(1000);
                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            // TODO Auto-generated method stub
                            Calendar c = Calendar.getInstance(); 
                            int rightNow = c.get(Calendar.SECOND) + c.get(Calendar.MINUTE)*60;
                            if(rightNow - lastUpdatedTime > 10) {
                                wirelessIcon.setImageResource(R.drawable.wirelessred);
                            }
                            else if(rightNow - lastUpdatedTime > 5) {
                                wirelessIcon.setImageResource(R.drawable.wirelessyellow);
                            }
                            else {
                                wirelessIcon.setImageResource(R.drawable.wirelessgreen);
                            }
                        }
                    });

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("Thread stoped:" + getClass().getSimpleName());
        }
    }

You set your lastUpdatedTime the same way you created rightNow whenever you call notifyDataSetChanged() method of your adapter.

Barışcan Kayaoğlu
  • 1,294
  • 3
  • 14
  • 35
  • And i suggest you use a handler to refresh your list view since handler is working on your UI thread. – Barışcan Kayaoğlu Mar 18 '14 at 11:49
  • where do i put this code. please see my edit post. I added my adapter class code. Thanks. – Thushara Mar 18 '14 at 12:04
  • It is a thread class to check your updated time. The if conditions in run() are the ones that you check your elapsed time. You can change the code block. You put it either in a separate file or as an inner class of your Activity, fragment or whatever you are using. You create an object when you start your activity and change your lastUpdatedTime wherever you refresh your list. Edit: Just realised i used this as an inner class since lastUpdatedTime is a variable of my super class. If you put this in a separate file, you need to prepare a getter setter methods of your lastUpdatedTime. – Barışcan Kayaoğlu Mar 18 '14 at 12:08