Android開発学習ノート(8):Handlerがマルチスレッドと非同期処理を実現


今回はHandlerについて簡単に説明しますが、なぜHandlerという機能特性が現れるのでしょうか.まず、従来の基本コントロールでは、基本的にActivityのonCreate(Bundle savedInstancesState)メソッドで呼び出され処理されていたが、場合によっては、ネットワーク上でソフトウェアをダウンロードするなど応答時間の長い操作を待つ必要があり、同様にActivityのこのメソッドに置くと、このメソッドを実行する際にActivity全体が動かず、ユーザーが待つしかない場合があり、このようなユーザ体験は非常に悪いものであり,このような処理方式がもたらす最良の結果は,しばらく待ってから所望の結果が得られることであり,悪い場合はNを長く待っても結果が出ず,Activityを誤報させることもあり,これらの状況を避けるためにHandlerの特性を導入し,スレッドキューのように非同期のメッセージ処理である.
まず例を見てみましょう
Handlerは認識する.
レイアウトファイルには2つのボタンがあります.
startとstopは、スレッドの開始と停止をそれぞれ制御します.
 

  
  
  
  
  1. <Button  
  2.     android:id="@+id/start" 
  3.     android:layout_height="wrap_content" 
  4.     android:layout_width="fill_parent" 
  5.     android:text="@string/start" 
  6. /> 
  7. <Button  
  8.     android:id="@+id/stop" 
  9.     android:layout_height="wrap_content" 
  10.     android:layout_width="fill_parent" 
  11.     android:text="@string/stop" 
  12. /> 
 
にある
Activityのコードは次のとおりです.
 

  
  
  
  
  1. import android.app.Activity; 
  2. import android.os.Bundle; 
  3. import android.os.Handler; 
  4. import android.view.View; 
  5. import android.view.View.OnClickListener; 
  6. import android.widget.Button; 
  7.  
  8. public class HandlerDemo1Activity extends Activity { 
  9.     Button startButton = null; 
  10.     Button endButton = null; 
  11.     Handler handler = new Handler(); 
  12.     /** Called when the activity is first created. */ 
  13.     @Override 
  14.     public void onCreate(Bundle savedInstanceState) { 
  15.         super.onCreate(savedInstanceState); 
  16.         setContentView(R.layout.main); 
  17.         startButton = (Button)findViewById(R.id.start); 
  18.         startButton.setOnClickListener(new StartListener()); 
  19.         endButton = (Button)findViewById(R.id.end); 
  20.         endButton.setOnClickListener(new EndListener()); 
  21.     } 
  22.      
  23.     class StartListener implements OnClickListener{ 
  24.  
  25.         @Override 
  26.         public void onClick(View arg0) { 
  27.             // TODO Auto-generated method stub 
  28.             handler.post(HandlerThread); 
  29.         } 
  30.          
  31.     } 
  32.      
  33.     class EndListener implements OnClickListener{ 
  34.         @Override 
  35.         public void onClick(View arg0) { 
  36.             // TODO Auto-generated method stub 
  37.             handler.removeCallbacks(HandlerThread); 
  38.         } 
  39.          
  40.     } 
  41.      
  42.     Runnable HandlerThread = new Runnable() { 
  43.          
  44.         @Override 
  45.         public void run() { 
  46.             // TODO Auto-generated method stub 
  47.             System.out.println("HandlerThread is Running......"); 
  48.             handler.postDelayed(HandlerThread, 3000); 
  49.         } 
  50.     }; 
 
ご覧のように
Activityでは、2つのボタンにそれぞれイベントリスナーをバインドし、Handlerのインスタンスを作成し、Runnableインタフェースを実装するスレッドHandlerThreadである匿名の内部クラスを作成します.
 

startボタンを押すとhandlerが実行する.post(HandlerThread);このコードは、Handlerが最初のスレッドであるため、HandlerThreadというスレッドをhandlerのスレッドキューに追加するスレッドキューを使用すると、run()メソッドがすぐに実行されます.run()メソッドではhandler.postDelayed(HandlerThread, 3000);もう一度HandlerThreadをhandlerのスレッドキューに入れます.ここでは3000 msの遅延が設定されています.これにより、プログラム全体が継続的に実行され、3000 ms毎にLogCatに「HandlerThread is Running......」が印刷される.
 
でも、注目すべきは、今は考えないで
handlerの出現により、これらの印刷操作が存在するスレッドとメインスレッドが分離されたが、実際にはそうではなく、ここには2つのスレッドが走っていない.これらの印刷された内容も、メインスレッドが飛び出したものである.現在のThreadの名前をonCreate関数の後と文を印刷する場所でThread.currentThread.getName()が印刷されると、同じでmainであることがわかります.これは、メインスレッドが飛び出していることを意味します.スレッドの起動にはstart()メソッドが必要であることを知っていますが、このプログラムではHandlerThreadをstartするのではなくrun()メソッドを直接呼び出しました.だからmainスレッドが走っているだけで不思議ではありません.
 
上の例から見ると、これは
Handlerがこのように使うと、非同期を実現していないため、メインスレッドで実行されているわけではありません.
 
そのため、私たちは別の方法で使用しなければなりません.
Handler.
実現するには
Handlerの非同期マルチスレッドは,MessageクラスとLooperクラスの2つのクラスを理解する必要がある.
それぞれ
Handlerオブジェクトにはメッセージキューがあり、キューには保存されたMessageオブジェクトがあり、obtainMessage()を使用してメッセージオブジェクトを取得できます.同時に、Messageオブジェクトは、2つの整数と1つのObjectを伝達するために使用され、できるだけMessageのarg 1とarg 2の2つの整数を使用してパラメータを伝達することができ、システム消費が最小(APIのように)であり、伝達データ量が比較的大きい場合、setData(Bundle a)の方法を使用することができ、Bundleオブジェクトは大まかにMapオブジェクトと見なすことができるが、そのKeyはStringであり、valueは限られたいくつかのタイプである.APIで確認できます.
 
Looperクラスには,メッセージキューから循環的にメッセージを取得できる機能があり,1つのスレッドで利用できる.
Looper,これにより,このスレッドはループしてメッセージキューにメッセージを取得し,メッセージキューが空であることを知ることができる.しかし、我々は一般的にLooperを直接作成して使用するのではなく、Androidが提供するHandlerThreadクラスではLooperの機能を実現しているので、HandlerThreadというクラスを使用すればよいので、HandlerThreadのオブジェクトでgetLooper()を呼び出してスレッドのLooperオブジェクトを得る.
 
次の例を見てみましょう
 
 

  
  
  
  
  1. import android.app.Activity; 
  2. import android.os.Bundle; 
  3. import android.os.Handler; 
  4. import android.os.HandlerThread; 
  5. import android.os.Looper; 
  6. import android.os.Message; 
  7.  
  8. public class HandlerDemo2Activity extends Activity { 
  9.     /** Called when the activity is first created. */ 
  10.     @Override 
  11.     public void onCreate(Bundle savedInstanceState) { 
  12.         super.onCreate(savedInstanceState); 
  13.         setContentView(R.layout.main); 
  14.         System.out.println("Activity---->"+Thread.currentThread().getName()); 
  15.         HandlerThread handlerThread = new HandlerThread("HandlerThread");// HandlerThread ,  
  16.         handlerThread.start();//  
  17.          
  18.         MyHandler myHandler = new MyHandler(handlerThread.getLooper());// MyHandler , Handler, MyHandler , Handler Handler(Looper looper) , Looper HandlerThread 。 
  19.         Message msg = myHandler.obtainMessage();//  
  20.         msg.sendToTarget();// Handler, myHandler, myHandler , handleMessage  
  21.     } 
  22.      
  23.     class MyHandler extends Handler{ 
  24.         public MyHandler() {//  
  25.             // TODO Auto-generated constructor stub 
  26.         } 
  27.          
  28.         public MyHandler(Looper looper){//  
  29.             super(looper);//  
  30.         } 
  31.          
  32.         @Override 
  33.         public void handleMessage(Message msg) {// Handler Message , , Message  
  34.             // TODO Auto-generated method stub 
  35.             System.out.println("Handler---->"+Thread.currentThread().getName()); 
  36.         } 
  37.     } 
 
上のコードは
LogCatのシステムoutの実行結果は次のとおりです.
Acitivity---->main
Handler---->HandlerThread
これで説明します.
Handlerは,LooperとMessageを組み合わせることで,主スレッドとの分離を実現でき,マルチスレッドと非同期処理を実現できる.
以上は個人的なHandlerにすぎませんが、添付ファイルは2つの例のコードで、参考にしてください.