【问题标题】:Android: Update ListView Items every 1 minuteAndroid:每 1 分钟更新一次 ListView 项目
【发布时间】:2012-10-16 13:44:31
【问题描述】:

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

1 个 TextView 显示了该 ListView 项的当前时间指定时间之间的时间间隔。

喜欢:5 分钟前发布

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

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

我尝试了什么:

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

但如果我不滚动(不调用 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。

但这看起来像一个熟悉的案例。

我怎样才能做到这一点?

谢谢

【问题讨论】:

    标签: android listview


    【解决方案1】:

    使用Handler 及其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。

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

    【讨论】:

    • 但没有 notifyDataSetChanged();仅在数据更改时才有效??
    • 它会刷新列表视图,不管数据是否改变。
    • 很好。有效。非常感谢。但我认为通常应用程序只会更新特定的 TextView 而不是整个 ListView 项目。如果 ListView 项目太复杂,这不会导致任何延迟或 UI 冻结吗?比如它包含 2-3 个图像,3-5 个 TextViews??
    • 它将更新每个可见 ListView 项中的每个视图,但这应该不是什么大问题。如果您担心渲染图像时的性能,您可以在尝试使其显示(可能)新图像之前始终检查 ImageView 是否为空
    • new Handler() 后缺少分号
    【解决方案2】:

    您还可以创建自定义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);
    }
    

    【讨论】:

    • 在这个例子中你将如何停止计时器?理论上它只是在列表删除视图时,但看起来没有办法做到这一点。
    • 如果你使用扩展BaseAdapter的自定义列表适配器,你需要调用ListAdapter.notifyDataSetChanged();并在适配器 getView();你调用的方法 stopTimer();
    【解决方案3】:

    使用内置的 TimerTask

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

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

    【讨论】:

      【解决方案4】:

      如果你想在主线程中重复一个动作,你应该使用 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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-17
        • 2020-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多