9

我的应用程序中有一个自定义 ListView,其中包含一个 ImageView 和 3-5 个 TextView。

TextViews 中的 1 个显示当前时间与为该 ListView 项指定的时间之间的时间间隔。

喜欢:发表于 5 分钟前

问题是,我怎样才能在不干扰 ListView 的情况下每分钟更新这个 TextView。

喜欢:如果我正在查看 ListView 5 分钟,则仅此 TextView 必须从 1 分钟更改为 2 分钟,依此类推,每个可见项目

我尝试了什么:

  1. 在getView()中设置这个 TextView使用System.currentTimeMillis() - givenTime[position];

但是如果我不滚动(不调用 getView)或更改项目的可见性,这里的 TextView 将不会得到更新。

  1. 每 1 分钟使用一次timeTask()线程并尝试更新每个项目的 TextView

这里的问题是我得到一个例外:

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

此外,我不知道如何更改 Activity 中每个 ListView 项目的 TextView。

但这似乎是一个熟悉的案例。

我怎样才能做到这一点?

谢谢你

4

4 回答 4

38

使用 aHandler及其postDelayed方法使列表的适配器无效,如下所示:

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

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

您只能在主 (UI) 线程中更新 UI。

通过在主线程中创建处理程序,您可以确保发布到处理程序的所有内容也在主线程中运行。

于 2012-10-16T13:50:23.060 回答
4

您还可以创建自定义TextView,它每秒或每分钟或每小时更新一次。这可以通过创建扩展TextView并在该类中添加 Handler 的类来轻松完成。好处是您不必更新整个 ListView,TextView 会自动更新。

例子:

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);
}

用法:

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

输出将如下所示:

 Posted 1 hours 5 minutes ago

如果您还想显示秒数,请将convertDatesToMinutes(long start, long end)方法更改为:

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);
}
于 2014-08-30T12:24:09.320 回答
3

使用内置的 TimerTask

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

这是一种可靠的做事方式。

于 2014-07-07T14:47:54.097 回答
1

如果你想在主线程中重复一个动作,你应该使用 Time.class 的“schedule”方法

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);
于 2017-03-21T16:37:04.213 回答