【Android】AsyncTaskを使ってみる

投稿者: | 2011年3月18日

AsyncTaskは、何かしらの重い処理(大きなファイルの読み込みやインターネットからのデータの取得等々)を行うとき、
UIスレッドを止めないようにするために使うクラスである。
もしUIスレッド上でこれらの重い処理を行うと、UIの表示が固まったように見えてしまい、操作性が良くない。
そこで、AsyncTaskを用い、重い処理は別のスレッドで行うようにし、UI側ではプログレスバー等を表示しておいて
別スレッドでの処理が終わったらプログレスバーの表示を消して元の操作に戻れるようにするようなプログラムを書いてみる。

以下がそのプログラムである。

package com.lesson.progress;

// インポートは省略

public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.button1).setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// ボタン押下時の処理
				// タスクを開始する
				new MyTask().execute(new Object[]{});
			}
		});
    }

    /**
     * タスクサンプル
     * ジェネリクスの型の意味は、
     * ・タスク開始時:doInBackground()に渡す引数の型
     * ・進捗率を表示させるとき:onProgressUpdate()に使う型
     * ・タスク終了時:doInBackground()の返り値の型
     */
    public class MyTask extends AsyncTask<Object, Integer, Boolean> {
        // 処理中ダイアログ
        private ProgressDialog progressDialog = null;

        // タスク開始前処理:UIスレッドで実行される
        @Override
        protected void onPreExecute() {
            // 進捗ダイアログ表示
            progressDialog = new ProgressDialog(Main.this);
            progressDialog.setMessage("now progressing...");
            progressDialog.setIndeterminate(false);
            progressDialog.setCancelable(false);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setProgress(0);
            progressDialog.setMax(100);

            progressDialog.show();

            Log.d("Main", "onPreExecute");
        }

        // プログレスバー更新処理: UIスレッドで実行される
        @Override
        protected void onProgressUpdate(Integer... values) {
        	progressDialog.setProgress(values[0]);

        	Log.d("Main", "onProgressUpdate " + values[0]);
        }


        // バックスレッドで実行する処理
        @Override
        protected Boolean doInBackground(Object... params) {

        	// 重い処理(10秒待つ)
        	try {
        		for( int i=0; i<100; i++ ){
        			// 進捗ダイアログに表示する値を更新する
        			// publishProgressを呼ぶと、UIスレッドでonProgressUpdateが実行される
        			publishProgress(i+1);

        			Thread.sleep(100);
        		}

			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			Log.d("Main", "doInBackground");

        	return true;
        }

        // タスク終了後処理:UIスレッドで実行される
        @Override
        protected void onPostExecute(Boolean result) {
            // 進捗ダイアログをクローズ
            progressDialog.dismiss();

            Log.d("Main", "onPostExecute");
        }
    }
}

基本的にはAsyncTaskを継承して、
doInBackground()等のメソッドを必要に応じてオーバーライドしていくことになるのだが、
これらのメソッドがどのスレッド上で行われるのかを把握しておく必要がある。
間違えると、Androidプログラミングでは禁止されている
「UIスレッド以外のスレッドがUIを操作する」プログラムを書いてしまう
ことになるので注意が必要となる。

用意したのはこんな画面。
ボタンを押すと・・・

このように、プログレスバーが表示される。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です