Androidスレッド間通信のMessageメカニズム

6217 ワード

詳細
Androidの下にもマルチスレッドの概念があり、C/C++では、サブスレッドは1つの関数であってもよいが、一般的にはいくつかのデータを処理するためにループ付きの関数であり、優先スレッドは複雑な演算過程にすぎないため、whileループを必要とせず、演算が完了し、関数が終了するとスレッドが破棄される可能性がある.制御が必要なスレッドについては、一般的には反発ロックと相互に関連してスレッドの進捗を制御し、一般的にはサブスレッドを作成します.1つのスレッドは、メッセージループを持つスレッドです.メッセージループは非常に有用なスレッド方式であり、かつてCでLinuxの下でメッセージループを実現するメカニズムを用いて、メッセージキューにデータを追加し、非同期でメッセージの戻りを待っていた.メッセージキューが空の場合、スレッドが保留され、新しいメッセージの追加が待たれます.これは汎用的なメカニズムです.Androidでは、ここのスレッドはメッセージループのあるスレッドとメッセージループのないスレッドに分かれており、メッセージループのあるスレッドには一般的にLooperという新しい概念があります.私たちのプライマリ・スレッド(UIスレッド)は、メッセージ・ループのスレッドです.このようなメッセージループのメカニズムに対して、私たちは新しいメカニズムHandleを導入して、私たちはメッセージループがあって、メッセージループの中に相応のメッセージを送信しなければなりません.カスタムメッセージは一般的に自分の対応する処理があって、メッセージの送信とクリア、メッセージの処理、これらをHandleの中にカプセル化して、HandleはLooperのあるスレッドに対してだけであることに注意してください.UIスレッドでもサブスレッドでも、Looperがあれば、メッセージキューに何かを追加して、対応する処理をすることができます.しかし、ここでもう一つ、UIに関するものであれば、サブスレッドに入れないことです.サブスレッドはUIを操作できないので、データやシステムなど他の非UIの操作しかできません.では、どのような状況で私たちのサブスレッドがLooperのあるスレッドと見なすことができますか?どうやってLooperのハンドルを手に入れますか?Looper.myLooper();現在のLooperLooperを取得getMainLooper()UIスレッドを取得したLopper Handleの初期化関数を見てみましょう.パラメータがなければ、現在のLooperがデフォルトで使用され、Looperパラメータがあれば、対応するスレッドのLooperが使用されます.スレッドでLooperを呼び出すとprepare()を使用すると、スレッドのメッセージキューが自動的に作成され、Looperが呼び出されます.loop();その後、メッセージループに入り、その後、メッセージを送信したり、メッセージを取得したり、メッセージを処理したりすることができます.このメッセージの送信方法とメッセージの処理方法は他のスレッドでHandleで行うことができますが、前提は私たちのHanleがこのサブスレッドのLooperを知っていることですが、サブスレッドでLooperを実行していない場合はmyLooper()は、一般的にサブスレッドのlooperは得られません.
public void run() {
            synchronized (mLock) {
                Looper.prepare();
               //do something
            }
            Looper.loop();
        }

だから多くの人はこのようにしています:私は直接サブスレッドの中でhandleを新築して、それからサブスレッドの中でメッセージを送信して、このようにすれば私たちのマルチスレッドの意味を失いました.
class myThread extends Thread{
             private EHandler mHandler ;
             public void run() {
                 Looper myLooper, mainLooper;
                 myLooper = Looper.myLooper ();
                mainLooper = Looper.getMainLooper ();
                String obj;
                if (myLooper == null ){
                         mHandler = new EHandler(mainLooper);
                         obj = "current thread has no looper!" ;
                }
                else {
                     mHandler = new EHandler(myLooper);
                     obj = "This is from current thread." ;
                }
                mHandler .removeMessages(0);
                Message m = mHandler .obtainMessage(1, 1, 1, obj);
                mHandler .sendMessage(m);
             }
  }
 
他のスレッドに私たちのhandleを制御させることができて、private EHandler mHandlerを制御することができます;外に置いて、このように私たちのメッセージと処理メッセージはすべて外で定義することができて、このように増加します
プログラム
コード#コード#
の美しさ、構造がよりはっきりしています.
いずれのHandleでも、public void handleMessage(Message msg)という関数をリロードする必要があります.この関数は私たちのメッセージ処理です.どのように処理するかは、あなた次第です.obtainMessageやsendMessageなどを通じてメッセージを生成し、送信します.removeMessages(0)はメッセージキューをクリアします.Googleは本当に知恵があって、このようなフレームワークの発生、私たちはコードを書くのがもっと楽になりました.ある时、私达のサブスレッドはUIを変えたいと思って、この时くれぐれもサブスレッドの中で修正しないでください、UIスレッドのLooperを得て、それからメッセージを送信します.Goole Music Appのソースコードを見てみましょう.MediaPlayback Activity.JAvaでは、mAlbumArtWorker=new Worker(「album art worker」);        mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());明らかにこの2つの文は、サブスレッドを構築しています.そしてこのサブスレッドはLooperのサブスレッドで、ここではmAlbumArtWorkerを使っています.getLooper()という関数は,サブスレッドのLooperを得る方法が一つしかないことを知っているからである:サブスレッドでLooperを呼び出すことである.myLooper()で、この関数は私たちのperpareの後に呼び出さなければ正しいLooperを得ることができませんが、彼はここでこのような何を使っていますか?ここでは、サブスレッドのprepareの後にmyLooper()というメソッドを呼び出し、メンバー変数に保存すると、このgetLooperはこれを返しますが、ここではマルチスレッドの際立った問題に遭遇し、同期します.親スレッドでmAlbumArtWorkerを呼び出します.getLooper()ですが、これが正しいlooperに戻るには、私たちのサブスレッドにprepareを実行するように要求しなければなりませんが、これは実際にサブスレッドが実行されています.私たちはどのように保証しますか?Googleがどのように実現したか見てみましょう.
 private class Worker implements Runnable {
        private final Object mLock = new Object();
        private Looper mLooper;
        
        /**
         * Creates a worker thread with the given name. The thread
         * then runs a [email=%7B@link]{@link[/email] android.os.Looper}.
         * @param name A name for the new thread
         */
        Worker(String name) {
            Thread t = new Thread(null, this, name);
            t.setPriority(Thread.MIN_PRIORITY);
            t.start();
            synchronized (mLock) {
                while (mLooper == null) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }
        
        public Looper getLooper() {
            return mLooper;
        }
        
        public void run() {
            synchronized (mLock) {
                Looper.prepare();
                mLooper = Looper.myLooper();
                mLock.notifyAll();
            }
            Looper.loop();
        }
        
        public void quit() {
            mLooper.quit();
        }
    }

スレッドクラスのコンストラクション関数はメインスレッドで完了していることを知っています.そのため、Workerのコンストラクション関数でスレッドを作成し、このスレッドを実行します.このスレッドの作成はRunnablを指定します.ここではWorker自体がメインスレッドでt.start()を呼び出します.その後,サブスレッドが作成され,workのrunメソッドの実行が開始される.次のコードは芸術的です
synchronized (mLock) {
                while (mLooper == null) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
 
私たちはサブスレッドがmLooperに値を付与するのを待っています.値を付与しなければ、私たちは待っています.そして、私たちのサブスレッドはrunメソッドを実行した後、mLooperに値を付与した後、workerに関数のwaitに十分であることを通知します.それから、私たちの構築関数は完成します.
mAlbumArtWorker = new Worker("album art worker");この文自体がブロックされています.サブスレッドを作成し、サブスレッドを開き、サブスレッドがmLooperに値を付与するのを待っています.値を付与した後、この関数は戻ります.そうすれば、私たちのサブスレッドのLooperの取得が絶対に正しいことを保証することができます.この構想は創意的です.参考に値する