AsyncTask非同期タスクの概要


実際のアプリケーションでは、ネットワーク接続、データベース操作など、時間のかかるタスクの処理が頻繁に発生しますが、これらの操作がメインスレッド(UIスレッド)に置かれていると、UIの偽死現象が発生します.悪名高いANR(プログラムの応答なし)は、ユーザー体験を大幅に割引します.Androidでは、メインスレッドで時間のかかる操作を完了することを望んでいません.サブスレッドで時間のかかる操作を完了することを選択することができますが、サブスレッドはメインスレッドインタフェース、すなわちUIインタフェースを直接制御することは許されません.時間のかかる操作を完了すると、UIはまだ動いていません.この矛盾を解決するために,AsyncTaskとHandlerの2つの非同期方式を用いることができる.以下、AsyncTaskに関する紹介と使い方についてまとめます.
1.AsyncTask(非同期タスク)
AndroidのUI操作スレッドは安全ではありません.
(1)Androidでは,メインスレッドでの時間のかかる操作を推奨しない,(ANRプログラムに応答しない)(Application No Responsding)(2)サブスレッドでUIコントロールを更新できない(3)Handle通信メカニズムを用いてサブスレッドとメインスレッドの通信を実現する(4)AsyncTaskでは,サブスレッドの時間のかかる操作の完了をパッケージ化し,メインスレッドでUIをリフレッシュする
AsyncTaskの実装:
(1)AsyncTaskを継承し,3つの汎用型を提供するだけで,(2)サブスレッドが時間のかかる操作を完了する一連のコールバックメソッドを実現し,メインスレッドリフレッシュUI(3)executeメソッドを用いて非同期タスクを実行する
2.AsyncTaskの使い方
(1)クラス継承AsyncTaskを書き,3つの汎用性を提供する.AsyncTask<Params,Progress,Result>
Params:非同期タスクを開始するときに入力するパラメータタイプProgress:バックグラウンドタスクの進捗を更新するタイプResult:バックグラウンドでタスクが完了した後に結果を返すタイプ、doInbackgroundの戻り値、この値はonPostExecute()メソッドの例に渡されます:AsyncTask<String, Integer, byte[]>パラメータを設定するときは通常、String...paramsです.このメソッドには0つ以上のパラメータがあります.パラメータは使用しないように設定できる場合があります.Void...でいいです.
(2)AsyncTask書き換えの方法は4つある
実行順序:1)onPreExecute():書き換える必要のないメソッドはメインスレッドで実行され、まずdoInBackgroundの前に呼び出される一般的にサブメソッドで初期化される動作例を実行します:ProgressDialog->プロンプト進捗ボックス
2)doInBackground(Params):書き換えなければならない方法はサブスレッドで実行され、システム(またはAsyncTask)に渡して呼び出し、自分でアクティブに呼び出さなくても伝わるパラメータタイプがAsyncTaskの最初のパラメータタイプpublishProgressである:AsyncTaskにタスクの進捗更新を通知する
3)onProgressUpdate(Progress):(doInBackgroundでpublishProgressを呼び出す)メインスレッドで通知タスク更新呼び出しを実行する方法に伝わるパラメータタイプがAsyncTaskの2番目のパラメータタイプである
4)onPostExecute(Result):UIの更新はメインスレッドで実行され、doInbackgroundから返された値に基づいてUIをリフレッシュする必要がありますdoInbackgroundメソッドの実行が完了すると、すぐに呼び出されたパラメータタイプがAsyncTaskの3番目のパラメータタイプになります
4つの方法:
1.onPreExecute()は、UIスレッドで実行される前処理を実行し、進捗バーコントロールの描画など、バックグラウンドタスクの準備を行うことができます.2.doInBackground(Params...)バックグラウンドプロセスが実行する具体的な計算はここで実現され、doInBackground(Params...)はAsyncTaskの鍵であり、この方法は再ロードしなければならない.この方法ではpublishProgress(Progress...)を使用して現在の進捗値を変更できます.3.onProgressUpdate(Progress...)はUIスレッドで実行されます.この方法はdoInBackground(Params...)でpublishProgress(Progress...)を使用するとトリガーされます.ここでは、進捗バーコントロールに対して進捗値に応じて具体的な応答を行うことができます.4.onPostExecute(Result)はUIスレッドで実行され、バックグラウンドタスクの結果を処理することができ、結果はdoInBackground(Params...)の戻り値である.このメソッドは、Resultがnullの場合、バックグラウンド・タスクが完了していない(キャンセルまたは例外が発生した)ことを示す場合にも頻繁に再ロードされます.
例を挙げると、リンクに基づいて画像をダウンロードします.
package org.mobile.train.day07_qf_asynctask_download;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

    private static final String IMAGE_URL = 
            "http://img1.imgtn.bdimg.com/it/u=1155447503,3876658488&fm=21&gp=0.jpg";

    private Button downloadImg;
    private ImageView image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        downloadImg = (Button) findViewById(R.id.downloadImage);
        image = (ImageView) findViewById(R.id.image);
    }
    //button    onClick  ,     
    public void downloadImg(View view) {
        //  DownloadTask       
        new DownloadTask().execute(IMAGE_URL);
    }

    /** *   AsyncTask,            ,        UI *      :    AsyncTask        ,       doInBackground(   URL) *      :              *      :doInBackground    ,      onPostExecute * */
    public class DownloadTask extends AsyncTask<String, Integer, byte[]>{

        //        
        ProgressDialog pd;

        /** *         *  doInBackground        *                 */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //   ProgressDialog
            pd = new ProgressDialog(MainActivity.this);
            //        title
            pd.setTitle("  ");
            //            
            pd.setMessage("     。。。");
            //  ProgressDialog
            pd.show();
        }

        /** *        ,            ,           *                */
        @Override
        protected byte[] doInBackground(String... params) {
            String url = params[0];
            byte[] bytes = getImageFromInternet(url);
            return bytes;
        }

        /** *        ,     doInBackground    ,   UI *  doInBackground       ,      */
        @Override
        protected void onPostExecute(byte[] result) {
            super.onPostExecute(result);
            //   byte[]   Bitmap
            Bitmap bm =BitmapFactory.decodeByteArray(result, 0, result.length);
            image.setImageBitmap(bm);
            //       
            pd.dismiss();
        }

    }

    public byte[] getImageFromInternet(String url) {
        //     
        InputStream is = null;
        //         
        byte[] data = null;
        //       ,
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        /** *         ,     */
        try {
            //  URL
            URL imageUrl = new URL(url);
            //      
            HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
            //      
            if(conn != null && conn.getResponseCode() == 200) {
                //int totalLenght = conn.getContentLength();
                //int currentLength = 0;
                is = conn.getInputStream();
                byte[] buffer = new byte[1024];
                int len = 0;
                while((len = is.read(buffer)) != -1){  //    1KB
                    baos.write(buffer);
                    baos.flush();
                }
                data = baos.toByteArray();
                return data;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(baos != null)
                    baos.close();
                if(is != null)
                    is.close();
            } catch (Exception e2) {
            }
        }
        return null;
    }
}