Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Update ListView Items every 1 minute

I have a Custom ListView in my application, containing an ImageView and 3-5 TextViews.

1 of the TextViews shows the time gap between the current time and the time specified for that ListView item.

Like: Posted 5 minutes ago

The question is, how can i update this TextView every minute without any disturbance to the ListView.

Like: if i am looking at the ListView for 5 minutes, just this TextView alone must change from 1 min to 2 mins so on for every item visible

What i tried:

  1. set this TextView in getView() using System.currentTimeMillis() - givenTime[position];

but here the TextView won't get updated if i am not scrolling (not calling the getView) or changing the visibility of the items.

  1. Use a timeTask() thread every 1 minute and try to update the TextView of every item

here the problem is i get an Exception:

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

moreover i have no idea how to change the TextView for every ListView item from the Activity.

But this looks like a familiar case.

How can i achieve this?

Thank You

like image 735
Archie.bpgc Avatar asked Oct 16 '12 13:10

Archie.bpgc


4 Answers

Use a Handler and its postDelayed method to invalidate the list's adapter as follows:

final Handler handler = new Handler()
handler.postDelayed( new Runnable() {

    @Override
    public void run() {
        adapter.notifyDataSetChanged();
        handler.postDelayed( this, 60 * 1000 );
    }
}, 60 * 1000 );

You must only update UI in the main (UI) thread.

By creating the handler in the main thread, you ensure that everything you post to the handler is run in the main thread also.

like image 77
JesperB Avatar answered Nov 20 '22 00:11

JesperB


Use the built in TimerTask

http://developer.android.com/reference/java/util/TimerTask.html

This is a solid way of doing things.

like image 32
slott Avatar answered Nov 19 '22 23:11

slott


You can also create custom TextView which updates it self every second or minute or hour. This can be done easily by creating class which extends TextView and add Handler inside that class. Benefits are that you don't have to update your whole ListView, TextView will update itself automatically.

Example:

public class TextViewTimeCounter extends TextView {
private long mStartTime = 0;
private long mTimeNow = 0;
private int mDelay = 0;
private String mPart1 = "";
private String mPart2 = "";

private Handler mHandler;

public TextViewTimeCounter(Context context) {
    super(context, null, 0);
}

public TextViewTimeCounter(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public TextViewTimeCounter(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public void startTimer(long delay, String part1, String part2){
    mStartTime = System.currentTimeMillis();
    mTimeNow = System.currentTimeMillis();
    mDelay = delay;
    mHandler = new Handler();
    mHandler.postDelayed(r, delay);
    convertDatesToMinutes(mStartTime, mTimeNow);
}

public void stopTimer(){
    if(mHandler != null){
        mHandler = null;
        mStartTime = 0;
        mTimeNow = 0;
    }
}

public boolean isTimerRunning(){
    return mHandler == null? false : true;
}


Runnable r = new Runnable() {
    @Override
    public void run(){
        mTimeNow += mDelay;
        convertDatesToMinutes(mStartTime, mTimeNow);
        if(mHandler != null){
            mHandler.postDelayed(r, mDelay);
        }
    }
};



public void convertDatesToMinutes(long start, long end){
    long secs = (end - start);
    long minute = (secs / (1000 * 60)) % 60;
    long hour = (secs / (1000 * 60 * 60)) % 24;
    String time = String.format(Locale.getDefault(), "%2d hours %2d minutes", hour, minute);

    setText(mPart1 + time + mPart2);
}

Usage:

TextViewTimeCounter timer = (TextViewTimeCounter)convertView.findViewById(R.id.start_logging_time_text);
timer.startTimer(10000, "Posted ", " ago");

Output will look like this:

 Posted 1 hours 5 minutes ago

If you want to display seconds also, change convertDatesToMinutes(long start, long end) method to this:

public void convertDatesToMinutes(long start, long end){
        long secs = (end - start);
        long second = (secs / 1000) % 60;
        long minute = (secs / (1000 * 60)) % 60;
        long hour = (secs / (1000 * 60 * 60)) % 24;
        String time = String.format(Locale.getDefault(), "%2d hours %2d minutes %2d seconds", hour, minute, second);
        setText(mPart1 + time + mPart2);
}
like image 24
user1888162 Avatar answered Nov 19 '22 23:11

user1888162


If you want repeat an action in the main thread in fractions of time you should use "schedule" method of the Time.class

mHandler = new Handler();
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
    @Override
    public void run() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                // run main thread code
            }
        });
    }
}, DELAY_TIME, PERIOD_TIME);
like image 1
pablopatarca Avatar answered Nov 20 '22 01:11

pablopatarca