AsyncTaskによるスレッドの利用

Androidでは普通にThreadを使うこともできるが、AsyncTaskを使うこともできる。AsyncTaskはThreadやRunnableを意識せずにメインスレッドとは別のスレッドで処理を行うことができるので、ある程度まとまった処理を行う場合には便利なクラスだ。

ただし、AsyncTaskを使ったとしてもメインスレッドとは別のスレッド、すなわちdoInBackgroundメソッドの中から直接UIを更新することはできない。この辺りはThreadやRunnableによる方法と変わらない。

スレッドとUIの基本

AsyncTaskを継承したサブクラスを用意する

AsyncTaskにはいくつか決まりごとがあるのでそれに沿って利用する必要がある。まずはAsyncTaskをextendsして処理のためのサブクラスを用意する。

        class ButtonTask extends AsyncTask<Long, Void, Date> {

            @Override
            protected Date doInBackground(Long... params) {
                // TODO Auto-generated method stub
                Log.d("onClick", "in Thread thread id = " + Thread.currentThread().getId());
                try {
                    Thread.sleep(params[0] * 1000); // n秒待つ
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return new Date();
            }

            @Override
            protected void onPostExecute(Date result) {
                // TODO Auto-generated method stub
                super.onPostExecute(result);
                Log.d("onClick", "date = " + result);
                Log.d("onClick", "runOnUiThread thread id = " + Thread.currentThread().getId());
                Toast.makeText(getApplicationContext(), "Click button1", Toast.LENGTH_SHORT).show();
            }

            @Override
            protected void onPreExecute() {
                // TODO Auto-generated method stub
                super.onPreExecute();
                Log.d("onClick", "before Thread thread id = " + Thread.currentThread().getId());
            }
        }

AsyncTaskのサブクラスを記述するときのGenerics(AsyncTaskの後ろの<T, T, T>)は最初から順にdoInBackground、onProgressUpdate、及びonPostExecuteの各メソッドに渡す可変長引数である。これらに指定できるのはクラスのみでint等のプリミティブは指定できない。これらのメソッドに引数を渡す必要がなければVoidを指定すれば良い。

AsyncTaskのメソッド

AsyncTaskの肝であるdoInBackgroundメソッドはメインスレッドとは別のスレッドで実行される。例えば、doInBackgroundメソッドだけにString型の引数を渡したい場合、extendsするのはAsyncTask<String, Void, Void>となる。AsyncTaskのサブクラスを記述するとき、少なくともこのdoInBackgroundメソッドだけはオーバライドしなければならない。

onPreExecuteメソッドはdoInBackgroundメソッドの実行前にメインスレッドで実行されるメソッドである。Androidのクラスの中にはメインスレッドでしか利用できないクラスもあるので、そういったものはこのonPreExecuteメソッドの中で利用する等すれば良いだろう。

onPostExecuteメソッドはdoInBackgroundメソッドの実行後にメインスレッドで実行されるメソッドである。指定すればdoInBackgroundメソッドの戻り値をこのメソッドの引数として受け取ることができ、別スレッドで実行した処理の結果を受けてUIを更新する等の処理を行うと良いだろう。

onProgressUpdateメソッドはpublishProgressメソッドの呼び出しをトリガーにメインスレッドで実行されるメソッドである。doInBackgroundで行っている処理の進行状況(doInBackgroundメソッド内でpublishProgressメソッドを呼び出す)をプログレスバーで表示するとき等に利用できる。

AsyncTaskを実行する

用意したAsyncTaskのサブクラスを実行するには、インスタンス化してexecuteメソッドを呼ぶだけである。doInBackgroundメソッドに渡す引数を指定した場合は、このexecuteメソッドに渡すことで生成されるスレッドにそれが伝播する。

        button1 = (Button)findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new ButtonTask().execute(new Long(5));
            }
        });

上記の例ではexecuteメソッドの引数として5を渡しているので、doInBackgroundメソッド内ではそれを基に5秒のwaitをしている。AsyncTaskを実行する上で大事なのは、このexecuteメソッドをメインスレッドから呼び出すこと、用意したAsyncTaskのサブクラスの各メソッドを直接呼び出さないこと、及び同じタスクを2度実行しないことである。

(2012/02/14)

新着情報
【iOS Objective-C, Swift Tips】アプリアイコンにバッジを表示(Swift)
【iOS Objective-C, Swift Tips】画像の向きを指定して保存する(Swift)
【iOS Objective-C, Swift Tips】UIImagePickerControllerの表示を日本語にする(Swift)

Copyright(C) 2004-2013 モバイル開発系(K) All rights reserved.
[Home]