スレッド処理の基本
ネットワークへのアクセスなどは、メインスレッドでは出来ないので、
別スレッドで行う。
こういう処理のときに、AsyncTaskを利用する。
また、AsyncTaskの経過処理を表示するのには、ProgressDialogが利用できる。
public void goTask() {
AsyncTask<Void,Integer,Void> task = new AsyncTask<Void,Integer,Void>() {
int total;
int count;
ProgressDialog dialog;
protected void createDialog() {
dialog = new ProgressDialog( this.MainActivity );
dialog.setTitle( "Working..." );
dialog.setMessage( "Wait for dummy");
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.setMax( 100 );
dialog.setProgress(0);
dialog.show();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
createDialog();
}
@Override
protected void onPostExecute(Void params) {
super.onPostExecute(params);
dialog.dismiss();
}
@Override
protected Void doInBackground(Void... params) {
count = 0;
total = 100;
for (int i=0;i<100;i++) {
count += 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress( count * 100 / total );
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
dialog.setProgress(values[0]);
super.onProgressUpdate(values);
}
};
task.execute( );
}
(このgoTaskメソッドは、何かボタンを押したら呼ばれるようにしておく)
デバイスの回転での問題点
これで動作するのだが、AsyncTaskが動作している間にデバイスを回転させてしまうと、プログレスバーが消えてしまう。
さらに、onPostExecuteのところのdialog.dismiss();のところでハングしてしまう。
この理由は、デバイスの回転にともなってアクティビティが削除/再生成されてしまうため。
アクティビティが再生成された場合でも、動作しているAsyncTaskが設定しているProgressDialogが削除された古い
アクティビティを保持して動作しているため、dismiss出来なずにエラーが発生してしまうからだ。
まず、Activityが破棄されたかどうかを知る必要がある。
このため、Activityに静的メンバとして、onCreateされた(最新の)Activityを保持することにする。
さらに、破棄された場合、新しいActivityから再度ProgressDialogを表示する必要があるが、サブスレッドからはGUIを
操作できないので、ハンドラを一つ用意しておく。
MainActivityに追加するフィールド
public static MainActivity currentActivity;
public Handler handler;
そして、onCreateメソッド内で、次のように定義しておく
currentActivity = this;
handler = new Handler();
また、goTaskで定義しているAsyncTasxk内でもMainActivityを保持しておく。
ループ処理中、もしもactivityがcurrentActivityと違っていたら、handler経由で再度、
ProgressDialogを表示する。
public void goTask() {
AsyncTask<Void,Integer,Void> task = new AsyncTask<Void,Integer,Void>() {
MainActivity activity;
int total;
int count;
ProgressDialog dialog;
protected void createDialog() {
dialog = new ProgressDialog( currentActivity );
dialog.setTitle( "Working..." );
dialog.setMessage( "Wait for dummy");
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.setMax( 100 );
dialog.setProgress(0);
dialog.show();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
activity = currentActivity;
createDialog();
}
@Override
protected void onPostExecute(Void params) {
super.onPostExecute(params);
if (activity == currentActivity) {
dialog.dismiss();
}
}
@Override
protected Void doInBackground(Void... params) {
count = 0;
total = 100;
for (int i=0;i<100;i++) {
count += 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (activity != currentActivity) {
activity = currentActivity;
activity.handler.post(new Runnable() {
@Override
public void run() {
createDialog();
}
});
}
publishProgress( count * 100 / total );
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
dialog.setProgress(values[0]);
super.onProgressUpdate(values);
}
};
task.execute( );
}
これで一応、画面を回転させても再度プログレスバーを表示して動作継続するようにできた。
ちょっと面倒なので、もう少し良い方法があればいいのだけど。
2013/7/27
最終更新:2013年07月26日 17:21