2017年2月27日月曜日

Android AsyncTask 使い方

目次へ



Viewの描画に関する処理は、UIスレッド(メインスレッド)で行う必要があります。
別のスレッドで何かを実行し、その途中、あるいは、別のスレッドでの処理が終わってから、UIスレッドで描画を行いたい場合には、AsyncTaskが便利です。

AsyncTaskの使い方は、Swingの、SwingWorkerの使い方と似ています。

また、Androidには、UIスレッド以外のスレッドから描画ができる特別なSurfaceViewというViewもあります。

■■■■サンプル■■■■

下のサンプルは、Activityが作成されると、onCreateメソッドの中でAsyncTaskを継承したクラスのインスタンスを作成し、スタートさせています。

AsyncTaskには、次のようなメソッドがあるので、オーバーライドして使います。
  • doInBackground⑤
    UIスレッドとは、別のスレッドで実行されるのでViewの描画などはできません
  • onPostExecute⑦
    doInBackgroundが終わると、UIスレッドで実行されるので、Viewの描画などが行えます
  • onProgressUpdate⑧
    doInBackgrounからpublishProgressを呼び出す⑥と実行され、UIスレッドで実行されます


また、④を見ると、ジェネリックで次のように型が3つ指定されています。
AsyncTask<Object, String, Integer>
この3つの型を①、②、③とすると、各メソッドの引数に対応します。
  • ① doInBackgroundの引数。

    ⑤のように、引数に...を書くのは、可変個引数の意味で、ここでは、引数があってもなくてもいいという意味で使っています。
    このクラスのインスタンスを作りexecuteメソッドを呼び出すとdoInBackgroundが呼び出されるため、execute呼び出し時にdoInBackgroundに渡したいものを渡しますが、 この例では、doInBackgroundに何も渡すものがないので、execute()として呼び出しています。

  • ② onProgressUpdateの引数。

    ⑥でpublishProgressを呼び出すと、onProgressUpdateが呼び出されるため⑥の引数が②の型となります。
    また、publishProgressが呼び出されるたびに、すぐにonProgressUpdateが呼び出されるとは限らず、複数回のpublishProgress呼び出しに対して、onProgressUpdateが1回にまとめられることがあるため、複数回の引数が可変個引数として、受け取れるようになっています。
    例では String... values となっています。

  • ③ onPostExecuteの引数

    doInBackgroundが終了すると、その戻り値を引数としてonPostExecuteが呼び出されますので、doInBackgroundの戻り値もこの型となります。

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 次の2行で別スレッドでの実行が始まる
        B b = new B();
        b.execute(); //①の型の引数を渡すが可変個引数なので無でもOK
    }
              //①     ②   ③
    class B extends AsyncTask<Object, String, Integer> { //④
                       
                   //①
        protected Void doInBackground(Object... params) { //⑤
            for(int i=0; i<10; i++) {
                publishProgress("i=" + i);  //⑥
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
         //③
            return new Integer(13);
        }

                  //③        
        protected void onPostExecute(Integer i) {  //⑦
            Toast.makeText(MainActivity.this,i+"で終わった",
               Toast.LENGTH_SHORT).show();

        }
                    //②
        protected void onProgressUpdate(String... values) {//⑧
            for(String v:values) {
                Toast.makeText(MainActivity.this, v, 
               Toast.LENGTH_SHORT).show();
            }
        }
    }
}



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村