我有一个后台工作繁重的应用程序。为了让我的 UI 保持活跃(并避免 ANR),我有一个不确定的 ProgressBar,我在后台工作之前显示并在完成时隐藏它。
这是我的进度条在我的活动的 xml 中声明的方式:
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:indeterminate="true"
android:visibility="gone" />
我在后台操作之前和之后切换可见性:
this.runOnUiThread(new Runnable() {
@Override
public void run() {
Activity.this.progress.setVisibility(View.VISIBLE);
}
});
this.runOnUiThread(new Runnable() {
@Override
public void run() {
Activity.this.progress.setVisibility(View.GONE);
}
});
在我的 Activity 的构造函数上:
this.progress = (ProgressBar) findViewById(R.my_activity.progress_id);
我的后台工作非常繁重(包括本地调用),但我创建了一个新的 Runnable 来完成这项工作。
问题是:使用progressBar,后台线程完成工作的时间增加了大约每秒300ms。当我运行 traceview 时,我可以看到每次我的 ProgressBar 刷新时,它都会停止后台线程来更新视图。
我尝试了两种方法:
- 将后台线程的优先级设置为 MAX_PRIORITY。
- 创建刷新率为 300 毫秒(默认为 50 毫秒)的自定义动画。
将这两者结合起来,我的一项操作的时间从 5900 毫秒到 4700 毫秒,但是由于刷新率较低,进度条不流畅,恐怕将后台线程优先级设置为 MAX 是不安全的。
还有什么我可以做的吗?
编辑:
AsyncTask 现在真的不可能重构了。
我使用 Chuck Norris 的解决方案更新的代码:
Activity.this.getHandler().sendEmptyMessage(
MyMessages.SHOW_PROGRESS_BAR);
Activity.this.getHandler().sendEmptyMessage(
MyMessages.HIDE_PROGRESS_BAR);
和
private Handler handler = new Handler() {
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MyMessages.SHOW_PROGRESS_BAR:
Activity.this.progress.setVisibility(View.VISIBLE);
break;
case MyMessages.HIDE_PROGRESS_BAR:
Activity.this.progress.setVisibility(View.GONE);
break;
default:
break;
}
};
};
这确实改进了我的应用程序,我不再需要将线程优先级设置为 Max,这是我的目标之一。
但我仍然想将我的动画恢复为 Android 的默认设置(每 50 毫秒刷新一次 ProgressBar)。当我这样做时,我在基准操作中损失了 1 秒。
我的基准:
同一操作的平均时间:
- 没有处理程序和android的默认进度条:5.1s
- 带handler和android的默认进度条:4.6s(线程优先到MAX的结果相同)
- 处理程序和自定义动画每 300 毫秒刷新一次:3.5 秒
- 处理程序和自定义动画每 150 毫秒刷新一次:3.8 秒
任何的想法?