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:
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.
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
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.
Use the built in TimerTask
http://developer.android.com/reference/java/util/TimerTask.html
This is a solid way of doing things.
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);
}
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With