分享

覚え書き: AndroidのAsyncTaskについて

 昵称27265735 2015-09-30
 今回は、AndroidのAsyncTaskについて。
知らない人のためにまずは、AsyncTaskの説明を。

Androidはメインスレッド内でDB接続等の時間のかかる処理を行うとその間、
画面はフリーズしてしまいます。
ボタンクリック時にDBへの登録処理を行い、
その間画面にはプログレスバー(くるくるするやつ)を表示しておきたいとします。
この時、メインスレッド(GUIスレッド)でプログレスバーを表示、そのまま同じスレッドで
登録処理を行うと、画面に表示されているプログレスバーは止まってしまいます。
これを解消するには、登録処理等のバックグラウンドで行いたい処理はメインスレッドとは
別のスレッドで行う必要があります。
この時、気をつけないと行けないのがバックグラウンドで動かしているスレッドから
UI操作を行うとエラーが発生してしまいます。
上記のような動作を簡単に実装できるのがAsyncTaskです。
以下に簡単なサンプルを。
  1. public class SampleActivity extends Activity {  
  2.   
  3.     /* ダイアログ(くるくるするやつ) */  
  4.     private ProgressDialog dialog;  
  5.   
  6.     @Override  
  7.     public void onCreate(final Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.sample);  
  10.   
  11.         final Button submitButton = (Button)findViewById(R.id.submitButton);  
  12.         submitButton.setOnClickListener(new OnClickListener() {  
  13.             @Override  
  14.             public void onClick(final View v) {  
  15.                 // くるくるを表示  
  16.                 dialog = new ProgressDialog(SampleActivity.this);  
  17.                 dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);  
  18.                 dialog.setMessage("登録中");  
  19.                 dialog.show();  
  20.   
  21.                 // AsyncTaskを開始  
  22.                 final SampleTask task = new SampleTask();  
  23.                 task.execute();  
  24.             }  
  25.         });  
  26.     }  
  27.   
  28.     /** 
  29.      * バックグラウンド処理を行うクラス 
  30.      */  
  31.     class SampleTask extends AsyncTask&ltVoid, Void, Void&gt {  
  32.   
  33.         /** 
  34.          * executeが実行された後に実行される。 
  35.          */  
  36.         @Override  
  37.         protected void doInBackground(Void... params) {  
  38.             // DB登録等のUIに関与しない処理  
  39.         }  
  40.   
  41.         /** 
  42.          * doInBackgroundの後に実行される。 
  43.          * このメソッド内ではUIを操作できる。 
  44.          */  
  45.         @Override  
  46.         public void onPostExecute(Void... params) {  
  47.             // くるくるを消去  
  48.             dialog.dismess();  
  49.         }  
  50.     }  
  51. }  

こんな感じになります。
ただAsyncTaskを内部クラスにするのがいやっていうか、だいたいここで行われる処理っていうのは
ビシネスロジックになることが多いので、Activityとは分離しておきたいので
別クラスにしたいところです。
ただ、そうするとAsyncTaskからUIを操作するために
AsyncTaskにActivityの参照を渡す必要が出てきてしまいます。
まあ、DB等にアクセスするためにはActivityが必要だったりするんですけど
画面個別のUI処理が入ってくる場合はどうしても、
画面固有のActivity(XxxxActivityみたいな)の型の参照を渡さなくてはいけなくて嫌な感じです。
できるだけ、Activityとして渡すに留めたい。そこで以下のような感じはどうでしょう?
まずは、以下のようなインターフェースを用意。
  1. public interface Callback {  
  2.   
  3.     /** 成功時のレスポンスコード */  
  4.     public static final int SUCCESS = 0;  
  5.   
  6.     /** 失敗時のレスポンスコード */  
  7.     public static final int ERROR = -1;  
  8.   
  9.     /** 
  10.      * コールバックメソッド 
  11.      */  
  12.     public void callback(final int responseCode, final int requestCode,  
  13.                                                     final Map<String, Object> resultMap);  
  14.   
  15. }  

次にActivity。
  1. public class SampleActivity extends BaseNoMapActivity implements Callback {  
  2.    /* ダイアログ(くるくるするやつ) */  
  3.     private ProgressDialog dialog;  
  4.   
  5.     private static final String REQUEST_CODE = "sample";  
  6.   
  7.     @Override  
  8.     public void onCreate(final Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.sample);  
  11.   
  12.         final Button submitButton = (Button)findViewById(R.id.submitButton);  
  13.         submitButton.setOnClickListener(new OnClickListener() {  
  14.             @Override  
  15.             public void onClick(final View v) {  
  16.                 // くるくるを表示  
  17.                 dialog = new ProgressDialog(SampleActivity.this);  
  18.                 dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);  
  19.                 dialog.setMessage("登録中");  
  20.                 dialog.show();  
  21.   
  22.                 // AsyncTaskを開始  
  23.                 final SampleTask task = new SampleTask(SampleActivity.this, REQUEST_CODE);  
  24.                 task.execute();  
  25.             }  
  26.         });  
  27.     }  
  28.   
  29.     /** 
  30.      * コールバックメソッド。 
  31.      * バックグラウンド処理終了後に呼び出される。 
  32.      */  
  33.     public void callback(final int responseCode, final int requestCode,  
  34.                                                     final Map<String, Object> resultMap) {  
  35.   
  36.         if (REQUEST_CODE.equals(requestCode)) {  
  37.             dialog.dismess();  
  38.         }  
  39.     }  
  40. }  

そして、AsyncTask。
  1. class SampleTask extends AsyncTask&ltVoid, Void, Void&gt {  
  2.   
  3.     /** コールバック */  
  4.     private Callback callback;  
  5.   
  6.     /** リクエストコード */  
  7.     private String requestCode;  
  8.   
  9.     /** コールバックの引数に渡す結果データ */  
  10.     private Map<String, Object> resultMap;  
  11.   
  12.     /** 
  13.      * コンストラクタ. 
  14.      */  
  15.     public SampleTask(final Callback callback, final String requestCode) {  
  16.        this.callback = callback;  
  17.        this.requestCode = requestCode;  
  18.   
  19.         resultMap = new HashMap<String, Object>();  
  20.     }  
  21.   
  22.     /** 
  23.      * executeが実行された後に実行される。 
  24.      */  
  25.     @Override  
  26.     protected void doInBackground(Void... params) {  
  27.         // DB登録等のUIに関与しない処理  
  28.         // resuletMapにActivityに渡した値を詰めたり  
  29.     }  
  30.   
  31.     /** 
  32.      * コールバックメソッドを実行する。 
  33.      */  
  34.     @Override  
  35.     public void onPostExecute(Void... params) {  
  36.         callback.callback(Callback.OK, requestCode, resultMap);  
  37.     }  
  38. }  
こんな感じです。
まずは、Callbackインターフェースですが、これでAsyncTackからActivityに処理を戻せるようにしています。
callbackメソッドによりActivityは「どのTaskを実行したのか」「成功したのか?」「結果データは?」と
といったものを受け取れるので、それに応じたUI処理を行えば良くなります。
考え方的にには、ActivityのstartActivityForResultとonActivityResultの考え方と同じです。
これなら、ある程度役割を分割できるのではないでしょうか。  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多