我试图从我的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);
答案 0 :(得分:2)
因为当您在refreshProgress(int id, int progress, boolean fromUser)
的源代码中看到方法ProgressBar.java
时,您会看到进度条在当前线程本身(UI线程)内更新。如果它不是UI线程,则使用Runnable更新Progress Bar。
此外,如果您想从非UI线程更新一次UI,那么您可以使用runOnUIThread(Runnable action)
答案 1 :(得分:1)
并非所有UI操作都必须在主线程上完成。可以从另一个线程调用的那些调度主线程上的视图或视图树的布局和/或绘制。在实践中,尝试辨别从非UI线程调用哪些方法是安全的并且哪些方法不安全并不是一个好主意。
要解决此问题,您应该使用AsyncTask
并在UI线程上运行的回调内执行所有UI操作:onPreExecute()
,onPostExecute()
和{{1} }。
答案 2 :(得分:1)
由于setProgress
方法已同步,因此它似乎被设计为从另一个线程调用。虽然文档没有明确说明。
答案 3 :(得分: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线程上发布runnable。我的猜测是这个设计有助于它从多个地方更新progressBar。
对于您必须执行的其他观看:
runonUiThread(new Runnable(){
@Override
public void run(){
//--- change the view--
}
});