Androidメッセージキュー(3)--マルチスレッドとメッセージ処理
三,Androidメッセージキュー--マルチスレッドとメッセージ処理
原文の住所:http://www.e800.com.cn/articles/2011/0720/491429_2.shtml
AndroidシステムのLooperはスレッドのメッセージキューとメッセージループを管理しています。具体的にはLooperのソースコードを参照してください。現在のスレッドのLooperオブジェクトはLoop.myLooper()によって得られ、Loop.getMainLooper()によって現在のプロセスのメインスレッドのLooperオブジェクトが得られます。前に述べたAndroidシステムのメッセージ・キューとメッセージ・ループは、特定のスレッドに対してのみ存在することができ、(もちろん、存在しなくてもよい)メッセージ・キューとメッセージ・ループ(Looper)は、特定のスレッドのメッセージを本スレッドに配信することができ、スレッドをまたぐことができない。しかし、作成されたワークスレッドは、デフォルトではメッセージループとメッセージキューがありません。このスレッドがメッセージキューとメッセージループを有するようにするには、スレッド内で最初にLooper.prepare()を呼び出してメッセージキューを作成し、次にLooper.loop()を呼び出してメッセージループに入る必要があります。次の例に示します
ActivityはUIスレッドであり、主スレッドで動作します。Androidシステムは起動時にActivityのためにメッセージ・キューとメッセージ・サイクルを作成します。詳細はActivityThread.javaファイルを参照してください。
Handlerの役割は、メッセージを特定のメッセージ・キューに追加し、メッセージ・キュー内のメッセージを配信して処理することである。Handlerを作成するときはループオブジェクトを指定し、指定しない場合は現在のスレッドのLooperで作成します。詳細な実装はロoperのソースコードを参照してください。
一つのActivityで複数のワークスレッドまたは他のコンポーネントが作成され、これらのスレッドまたはコンポーネントがActivityのメインスレッドメッセージキューに彼らのメッセージを入れると、このメッセージはメインスレッドで処理される。メインスレッドは一般にインタフェースの更新操作を担当しており、Androidシステムにおけるwegetはスレッドセキュリティではないので、このような方法はAndroidインターフェースの更新を良好に行うことができる。この方式はAndroidシステムで広く使われています。もう一つのスレッドはどうやってメッセージをメインスレッドのメッセージキューに入れますか?答えは、Handleオブジェクトを介して、HandlerオブジェクトがメインスレッドのLooperで作成される限り、HandlerのsendMessageなどのインターフェースを呼び出して、メッセージをキューに入れるのは、メインスレッドに入るメッセージ待ち行列です。そして、メッセージは、Handlerメインスレッドにおいて、handlerのhandleMessageインターフェースを呼び出して処理される。この中にスレッド同期の問題があります。まず以下の例を参考にして、Handlerオブジェクトのスレッドモデルを理解してください。
09-10 23:40:51.478:DEBUG/Handler(302):The main thread id=1 09-10 23:40:51.569:DEBUG/Handler(302):The worker thread id=8 09-10 23:40:52 DEBUG/Handler(302):The handler=1
メッセージ処理はメインスレッドで処理されており、メッセージ処理関数では、リフレッシュインターフェースを含む主スレッド内の任意のリソースを安全に呼び出すことができることを示している。作業スレッドと主スレッドは異なるスレッドで動作しますので、この2つのスレッド間の競合関係に注意しなければなりません。
上記の例では、ワークスレッドにおいて、主スレッドhandlerオブジェクトにアクセスし、handlerを呼び出したオブジェクトがメッセージキューにメッセージを追加していることに気づくかもしれない。この過程でメッセージキューのデータが一致しない問題がありますか?答えはhandlerオブジェクトに問題がないということです。handlerオブジェクトが管理するLooperオブジェクトはスレッドが安全であるため、参加メッセージからメッセージキューへの参加やメッセージの読み出しは同期オブジェクト保護があります。具体的にはLooper.javaファイルを参照してください。上記の例では、handlerオブジェクトを修正していないので、handlerオブジェクトにデータが一致しない問題が発生する可能性はありません。
上記の分析を通して、次のような結論が得られます。
1、ワークスレッドを通して画面を更新する場合は、handlerオブジェクトの使用を推奨します。
2、ワークスレッドとメインスレッドの競合関係に注意する。handlerオブジェクトは、メインスレッドで作成されています(作業スレッドを起動した後は、修正しないでください。そうでないとデータが一致しません。)。そして、作業スレッドでは、安心してメッセージを送るためのSendMessageなどのインターフェースを呼び出すことができます。
3、2つのhanderオブジェクト以外の任意のプライマリスレッドのメンバ変数がワークスレッドで呼び出された場合、スレッド同期問題を慎重に考慮する。同期オブジェクトを追加して変数を保護する必要がある場合。
4、handlerオブジェクトのhandleMessageインターフェースはメインスレッドで呼び出されます。この関数では、任意の変数と関数をプライマリスレッドに呼び出すことができ、UIを更新するタスクが完了します。
5、Androidの多くのAPIもHandlerというスレッド特性を利用して、リベート関数のバリエーションとして使用者に通知しています。このように、Androidフレームは、スレッドにおいて、スレッド同期の問題を心配することなく、そのスレッドにメッセージを送ることができる。
Androidメッセージ処理機構を深く理解することは、アプリケーション開発にとって非常に重要であり、スレッド同期についてより深く認識することもできる。
原文の住所:http://www.e800.com.cn/articles/2011/0720/491429_2.shtml
AndroidシステムのLooperはスレッドのメッセージキューとメッセージループを管理しています。具体的にはLooperのソースコードを参照してください。現在のスレッドのLooperオブジェクトはLoop.myLooper()によって得られ、Loop.getMainLooper()によって現在のプロセスのメインスレッドのLooperオブジェクトが得られます。前に述べたAndroidシステムのメッセージ・キューとメッセージ・ループは、特定のスレッドに対してのみ存在することができ、(もちろん、存在しなくてもよい)メッセージ・キューとメッセージ・ループ(Looper)は、特定のスレッドのメッセージを本スレッドに配信することができ、スレッドをまたぐことができない。しかし、作成されたワークスレッドは、デフォルトではメッセージループとメッセージキューがありません。このスレッドがメッセージキューとメッセージループを有するようにするには、スレッド内で最初にLooper.prepare()を呼び出してメッセージキューを作成し、次にLooper.loop()を呼び出してメッセージループに入る必要があります。次の例に示します
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
このようにあなたのスレッドはメッセージ処理機構を持っています。Handlerでメッセージ処理を行います。ActivityはUIスレッドであり、主スレッドで動作します。Androidシステムは起動時にActivityのためにメッセージ・キューとメッセージ・サイクルを作成します。詳細はActivityThread.javaファイルを参照してください。
Handlerの役割は、メッセージを特定のメッセージ・キューに追加し、メッセージ・キュー内のメッセージを配信して処理することである。Handlerを作成するときはループオブジェクトを指定し、指定しない場合は現在のスレッドのLooperで作成します。詳細な実装はロoperのソースコードを参照してください。
一つのActivityで複数のワークスレッドまたは他のコンポーネントが作成され、これらのスレッドまたはコンポーネントがActivityのメインスレッドメッセージキューに彼らのメッセージを入れると、このメッセージはメインスレッドで処理される。メインスレッドは一般にインタフェースの更新操作を担当しており、Androidシステムにおけるwegetはスレッドセキュリティではないので、このような方法はAndroidインターフェースの更新を良好に行うことができる。この方式はAndroidシステムで広く使われています。もう一つのスレッドはどうやってメッセージをメインスレッドのメッセージキューに入れますか?答えは、Handleオブジェクトを介して、HandlerオブジェクトがメインスレッドのLooperで作成される限り、HandlerのsendMessageなどのインターフェースを呼び出して、メッセージをキューに入れるのは、メインスレッドに入るメッセージ待ち行列です。そして、メッセージは、Handlerメインスレッドにおいて、handlerのhandleMessageインターフェースを呼び出して処理される。この中にスレッド同期の問題があります。まず以下の例を参考にして、Handlerオブジェクトのスレッドモデルを理解してください。
package com.simon;
import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.os.Handler;
public class MyHandler extends Activity {
static final String TAG = "Handler";
Handler h = new Handler(){
public void handleMessage (Message msg)
{
switch(msg.what)
{
case HANDLER_TEST:
Log.d(TAG, "The handler thread id = " + Thread.currentThread().getId() + "
");
break;
}
}
};
static final int HANDLER_TEST = 1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "The main thread id = " + Thread.currentThread().getId() + "
");
new myThread().start();
setContentView(R.layout.main);
}
class myThread extends Thread
{
public void run()
{
Message msg = new Message();
msg.what = HANDLER_TEST;
h.sendMessage(msg);
Log.d(TAG, "The worker thread id = " + Thread.currentThread().getId() + "
");
}
}
}
この例では主に印刷であり,このような処理機構は各モジュールにおけるスレッドの状況である。以下は私のマシンの運転結果です。09-10 23:40:51.478:DEBUG/Handler(302):The main thread id=1 09-10 23:40:51.569:DEBUG/Handler(302):The worker thread id=8 09-10 23:40:52 DEBUG/Handler(302):The handler=1
メッセージ処理はメインスレッドで処理されており、メッセージ処理関数では、リフレッシュインターフェースを含む主スレッド内の任意のリソースを安全に呼び出すことができることを示している。作業スレッドと主スレッドは異なるスレッドで動作しますので、この2つのスレッド間の競合関係に注意しなければなりません。
上記の例では、ワークスレッドにおいて、主スレッドhandlerオブジェクトにアクセスし、handlerを呼び出したオブジェクトがメッセージキューにメッセージを追加していることに気づくかもしれない。この過程でメッセージキューのデータが一致しない問題がありますか?答えはhandlerオブジェクトに問題がないということです。handlerオブジェクトが管理するLooperオブジェクトはスレッドが安全であるため、参加メッセージからメッセージキューへの参加やメッセージの読み出しは同期オブジェクト保護があります。具体的にはLooper.javaファイルを参照してください。上記の例では、handlerオブジェクトを修正していないので、handlerオブジェクトにデータが一致しない問題が発生する可能性はありません。
上記の分析を通して、次のような結論が得られます。
1、ワークスレッドを通して画面を更新する場合は、handlerオブジェクトの使用を推奨します。
2、ワークスレッドとメインスレッドの競合関係に注意する。handlerオブジェクトは、メインスレッドで作成されています(作業スレッドを起動した後は、修正しないでください。そうでないとデータが一致しません。)。そして、作業スレッドでは、安心してメッセージを送るためのSendMessageなどのインターフェースを呼び出すことができます。
3、2つのhanderオブジェクト以外の任意のプライマリスレッドのメンバ変数がワークスレッドで呼び出された場合、スレッド同期問題を慎重に考慮する。同期オブジェクトを追加して変数を保護する必要がある場合。
4、handlerオブジェクトのhandleMessageインターフェースはメインスレッドで呼び出されます。この関数では、任意の変数と関数をプライマリスレッドに呼び出すことができ、UIを更新するタスクが完了します。
5、Androidの多くのAPIもHandlerというスレッド特性を利用して、リベート関数のバリエーションとして使用者に通知しています。このように、Androidフレームは、スレッドにおいて、スレッド同期の問題を心配することなく、そのスレッドにメッセージを送ることができる。
Androidメッセージ処理機構を深く理解することは、アプリケーション開発にとって非常に重要であり、スレッド同期についてより深く認識することもできる。