バックグラウンドでの作業が多いアプリがあります。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);
}
});
私のアクティビティのコンストラクターについて:
this.progress = (ProgressBar) findViewById(R.my_activity.progress_id);
私のバックグラウンド作業は非常に重いです(ネイティブコールを含む)が、その仕事をするために新しいRunnableを作成します。
問題は次のとおりです。progressBarを使用すると、作業をバックグラウンドで終了するまでの時間が1秒あたり約300ミリ秒長くなります。traceviewを実行すると、ProgressBarが更新されるたびに、バックグラウンドスレッドが停止してビューが更新されることがわかります。
私は2つのアプローチを試しました:
- バックグラウンドスレッドの優先度をMAX_PRIORITYに設定します。
- リフレッシュレートが300ms(デフォルトは50ms)のカスタムアニメーションを作成します。
これら2つを組み合わせると、1つの操作の時間は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;
}
};
};
これによりアプリケーションが本当に改善され、スレッドの優先度を最大に設定する必要がなくなりました。これが私の目標の1つでした。
ただし、アニメーションをAndroidのデフォルトに戻したい(50ミリ秒ごとにProgressBarを更新する)。そうすると、ベンチマーク操作で1を失います。
私のベンチマーク:
同じ操作の平均時間:
- ハンドラーとAndroidのデフォルトのプログレスバーなし:5.1秒
- ハンドラーとAndroidのデフォルトのプログレスバーを使用した場合:4.6秒(MAXに対するスレッドの優先度と同じ結果)
- 300msごとに更新されるハンドラーとカスタムアニメーション:3.5秒
- 150ミリ秒ごとに更新されるハンドラーとカスタムアニメーション:3.8秒
何か案が?