0

我试图从我的 TimerTask 更改我的 UI,但我认识到这是不可能的,因为 TimerTask 在后台线程中运行,并且不允许后台线程更改 UI。
现在我的问题是:我正在从 TimerTask 更改 ProgressBar 和 TextView,它适用于 ProgressBar,但不适用于 TextView。为什么我可以更改 ProgressBar?

为什么 ProgressBar 对此没有任何问题?

timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            int time = playerTimer(time);

            progressbar.setProgress(time);
            playerTime.setText(time);

        }

    }, 0, 1000);
4

4 回答 4

2

这是因为当您refreshProgress(int id, int progress, boolean fromUser)在源代码中看到该方法时,ProgressBar.java您会看到进度条在当前线程本身(即 UI 线程)内更新。如果它不是 UI 线程,则使用 Runnable 更新进度条。

此外,如果您想从非 UI 线程更新 UI,那么您可以使用runOnUIThread(Runnable action)

于 2013-08-03T07:06:53.070 回答
1

并非所有 UI 操作都必须在主线程上完成。可以从另一个线程调用的那些在主线程上调度视图或视图树的布局和/或绘制。在实践中,尝试辨别哪些方法可以安全地从非 UI 线程调用以及哪些方法不安全并不是一个好主意。

为了解决这个问题,您应该AsyncTask在 UI 线程上运行的回调中使用并执行所有 UI 操作:onPreExecute()onPostExecute()onProgressUpdate().

于 2013-08-03T07:04:56.330 回答
1

由于该setProgress方法是同步的,它似乎被设计为从另一个线程调用。该文档没有明确说明这一点。

于 2013-08-03T07:07:18.513 回答
1

ProgressBar类旨在使用它。这是执行此操作的代码:

  if (mUiThreadId == Thread.currentThread().getId()) {
        doRefreshProgress(id, progress, fromUser, true);
    } else {
        if (mRefreshProgressRunnable == null) {
            mRefreshProgressRunnable = new RefreshProgressRunnable();
        }

        final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
        mRefreshData.add(rd);
        if (mAttached && !mRefreshIsPosted) {
            post(mRefreshProgressRunnable); //--posted to view's thread --
            mRefreshIsPosted = true;
        }
    }

这是检查您是否在 UI 线程上。如果不是它在 UI 线程上发布一个可运行的。我的猜测是这种设计有助于它从多个地方更新progressBar。

对于其他视图,您必须这样做:

runonUiThread(new Runnable(){

 @Override
 public void run(){
   //--- change the view--
 }

});
于 2013-08-03T07:18:17.997 回答