Androidマルチスレッド通信メカニズム


AndroidではUIスレッド外のスレッドをワークスレッドにしています.ネットワークの安価な接続、IO操作など、メインスレッドで時間のかかる操作はできません.そのため、時間のかかる操作を別のスレッドに配置し、操作が完了したら、メインスレッドに対応する応答を通知することができます.これはスレッド間通信方式を把握する必要がある.Androidは2つのスレッド間通信方式を提供している.1つはAsyncTaskメカニズムであり、もう1つはHandlerメカニズムである.
1.スレッド間通信方式のAsyncTaskメカニズム:AsyncTask非同期タスク、つまりスレッドが実行されている場合、バックグラウンドで非同期の操作を実行することもできます.AsyncTaskではバックグラウンド操作が可能になり、ワークスレッドとHandlerメカニズムを使用した場合はUIスレッドに結果を返します.AsyncTaskは短時間の操作にのみ適しています.
1.1 AsyncTask AsyncTaskは継承によってのみ使用できます.

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {   //         ,          ,        
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }
    //           ,    UI        ,    UI      
     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }
    //       ,      UI      ,
     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

AsyncTaskのいくつかのパラメータ:Params:実行するタスクのパラメータタイプProgress:バックグラウンド実行タスクの進捗Result:バックグラウンド実行タスクの最終結果
AsyncTaskタスクが実行されると、4つのステップが実行されます.onPreExecute()タスク実行前に呼び出され、UIスレッドでdoInBackground()を実行するUI初期化作業を行います.バックグラウンドでタスクを実行し、ワークスレッドでonProgressUpdate()を実行します.バックグラウンドでタスクを実行している進捗状況を更新し、メインスレッドで作業します.ユーザーにタスクの現在の完了進捗を通知するために使用できます.このメソッドを呼び出す前に、2番目のステップでpublishProgress(Progress...)を呼び出して進捗をこのメソッドに渡す必要があります.onPostExecute():バックグラウンドタスクが完了すると、このメソッドに結果が返され、UIスレッドで呼び出され、UIを更新できます.
AsyncTaskを使用する場合、注意すべき点:
AsyncTaskクラスは、Android Jelly_にロードされるUIスレッドにロードする必要があります.Beanバージョン以降は自動的に完了します.
AsyncTaskクラスはUIスレッドでインスタンス化する必要があります.
手動でonPreExecute()、doInBackground(Params...)、publishProgress(Progress...)、onPostExecute(Result)メソッドを呼び出さないでください.これらのメソッドはシステムによって自動的に呼び出されます.
execute(Params...)メソッドは、UIスレッドでこの文を実行するなど、UIスレッドで呼び出さなければならない:new DownloadFilesTask().execute(url 1,url 2,url 3);私たちは他の仕事をする必要はありません.このダウンロードタスクは自動的にバックグラウンドで実行され、AsynacTaskタスクは一度しか実行できません.
2.スレッド間通信方式のHandlerメカニズム:*Handler、MessageオブジェクトとRunnableオブジェクトの送信と処理;Looperは、MessageQueueからメッセージ(Message)オブジェクトを取り出し、Handler処理に送信する.MessageQueue:Handlerが発行したメッセージを格納するメッセージキュー.Message:メッセージのタイプで、いくつかのインスタンスオブジェクトが含まれています.
whatは、メッセージを記述するためにユーザ定義int型メッセージコードである.objは、メッセージ送信に伴うユーザがオブジェクトを指定する.target、メッセージを処理するHandler;1つのHandlerは1つのLooperにのみ関連付けられ、1つのMessageも1つのターゲットHandlerオブジェクトにのみ関連付けられます.1つのLooperオブジェクトは1つのMessageQueueを持っていますが、複数の異なるHandlerオブジェクトも同じオブジェクトに関連付けることができます.すなわち,Handlerはメッセージ共有の目的を達成するためにMessageQueueを共有することができる.AndroidがHandlerメカニズムでマルチスレッド間通信を実現する原理でもある.
Handlerオブジェクトは1つのLooperにのみ関連付けられていますが、この関連付けはいつ実現されますか?答えは、Handlerオブジェクトが作成されたときです.UIスレッドは作成時にHandlerオブジェクトとLooperオブジェクトを持つ.(作業スレッドは、Looper.prepare()を呼び出してLooperオブジェクトを作成する必要があります)、プライマリスレッドで作成されたHandlerオブジェクトは、デフォルトでプライマリスレッドのLooperオブジェクトに関連付けられます.(Handlerオブジェクトが作成されると、このスレッドのLooperオブジェクトに関連付けられます).さらに,UIマスタースレッドで作成したHandlerをワークスレッドに渡すことができ,ワークスレッドでこのHandlerオブジェクトで処理されるメッセージはUIマスタースレッドのMessageQueueで処理される.
Androidスレッド間の非同期通信を実現するためにHandlerメカニズムを使用する原理を理解し、この4つのコアクラスを詳細に理解します.
2.1 Handler Handlerは、Objectから継承され、MessageオブジェクトまたはRunnableオブジェクトを送信または処理するために使用されます.Handlerは作成時に、現在のスレッドのLooperオブジェクトに関連付けられます(現在のスレッドのLooperオブジェクトが空または存在しない場合、どのように異常を報告するかは、スレッドでLooper.prepare()をアクティブに呼び出してLooperオブジェクトを作成する必要があります).Handlerを使用する役割は、後のプロセスでMessageオブジェクトを送信および処理し、他のスレッドにある動作を完了させることです(たとえば、作業スレッドでMessageオブジェクトをHandlerで送信し、UIスレッドがUIを更新すると、UIスレッドはMessage QueueでこのMessageを取得します(Messageオブジェクトを取り出すのは、それに関連付けられたLooperオブジェクトによって完了します)を選択し、対応する応答を行います).
HandlerはpostでRunnableオブジェクトの送信を完了し、sendMessageでメッセージを送信する.Postは、メッセージキューにRunnableオブジェクトを送信することを許可します.その方法は、post(Runnable)、postDelayed(Runnable、long)、postAtTime(Runnable、long)、handlerはsendMessageでMessageオブジェクトをメッセージキューに送信します.その方法はsendEmptyMessage(int)、sendMessage(Message)、sendMessage Delayed(Message,long)、sendMessageAtTime(Message,long);
Handlerがpostシステムを介してRunnableオブジェクトをMessageQueueキューに送信する場合、このRunnableオブジェクトのrun()メソッドは、Handlerオブジェクトの作成時にスレッドが実行されます.HandlerがsendMessageアーキテクチャを介してMessageをMessage Queueに送信する場合、handleMessage()メソッドを書き換える必要があります.handleMessage()メソッドは、Handlerオブジェクトの作成時に動作するスレッドです.
2.2 Mssage Messageは、Handler処理に送信できる任意のデータを含むメッセージオブジェクトを定義するために使用される.新しいオブジェクトを再生成するのではなく、Messageの構築方法でMessageオブジェクトを取得するには、Message.obtain()またはHandler.obtainMessage()を使用します.このオブジェクトは再生成されます.
Message{
int arg1;//              Integer  ,             
int agr2;//   arg1
Object obj; //             ,             
int what; //         ;
//              ,      Bundle   ;
void setData(Bundle data);
Bundle getData();               ;
//           
......

2.3 MessageQueue MessageQueue Looperによってスケジュールされたメッセージのリストを保存し、Looperに関連付けられたHandlerオブジェクトを介してMessageQueueにメッセージを追加する.2.4 Looper Looperはスレッドのためにメッセージを実行する循環キューであり、主にMessageとHandlerのインタラクション機能を完成する.スレッドのデフォルトでは、メッセージ・キューを管理するLooperインスタンスは提供されません.メッセージ・キューを管理するために、スレッド内でLooper.prepare()メソッドをアクティブに呼び出してLooperオブジェクトをインスタンス化する必要があります.LooperオブジェクトはMessageQueueが空かどうかを判断し続け、空でなければMessageを対応するHandler処理に取り出す.空の場合、Looperは新しいメッセージがMessageQueueに入るまでブロック状態になります.
実は、AndroidでHandlerメカニズムによってマルチスレッド間を非同期で処理する通信とは、複数のスレッド間で1つのMessageQueueを共有し、作業スレッドがMessageをMessageQueueに送信し、UIスレッドまたは他のスレッドがMessageQueueで取り出し、対応する処理を行うことである.
補足説明:サブスレッドによるUI更新の4つの方法:1.handlr.post(Runnable r)2.handler.handlerMessage(Message msg)3.runOnUiThread(Runnable r)4.View.post(Runnable r)