Androidでのマルチスレッド


Androidの下にもマルチスレッドの概念があり、C/C++では、サブスレッドは1つの関数であってもよいが、一般的にはいくつかのデータを処理するためにループ付きの関数であり、優先スレッドは複雑な演算過程にすぎないため、whileループを必要とせず、演算が完了し、関数が終了するとスレッドが破棄される可能性がある.制御が必要なスレッドについては、一般的には反発ロックと相互に関連してスレッドの進捗を制御し、一般的にはサブスレッドを作成します.1つのスレッドは、メッセージループを持つスレッドです.
メッセージループは非常に有用なスレッド方式であり、かつてCでLinuxの下でメッセージループを実現するメカニズムを用いて、メッセージキューにデータを追加し、非同期でメッセージの戻りを待っていた.メッセージキューが空の場合、スレッドが保留され、新しいメッセージの追加が待たれます.これは汎用的なメカニズムです.
Androidでは、ここのスレッドはメッセージループのあるスレッドとメッセージループのないスレッドに分かれており、メッセージループのあるスレッドには一般的にLooperという新しい概念があります.私たちのプライマリ・スレッド(UIスレッド)は、メッセージ・ループのスレッドです.このようなメッセージループのメカニズムに対して、私たちは新しいメカニズムHandleを導入して、私たちはメッセージループがあって、メッセージループの中に相応のメッセージを送信しなければなりません.カスタムメッセージは一般的に自分の対応する処理があって、メッセージの送信とクリア、メッセージの処理、これらをHandleの中にカプセル化して、HandleはLooperのあるスレッドに対してだけであることに注意してください.UIスレッドでもサブスレッドでも、Looperがあれば、メッセージキューに何かを追加して、対応する処理をすることができます.
しかし、ここでもう一つ、UIに関するものであれば、サブスレッドに入れないことです.サブスレッドはUIを操作できないので、データやシステムなど他の非UIの操作しかできません.
では、どのような状況で私たちのサブスレッドがLooperのあるスレッドと見なすことができますか?どうやってLooperのハンドルを手に入れますか?
Looper.myLooper();現在のLooperを取得
Looper.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を得て、それからメッセージを送信します.
 
高煥堂のコードを見てみましょう.
 
//class ac01 extends Activity {//……… public void onClick(View v) { switch (v.getId()){ case 101: t = new myThread(); t .start(); break ; case 102: finish(); break ; } }//------------------------------------------------------ class EHandler extends Handler { public EHandler(Looper looper) { super (looper); } @Override public void handleMessage(Message msg) { tv .setText((String)msg. obj ); } }//------------------------------------------------------ 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); } } }
 
 
まったく何が起こっているのか分からない.犬の糞だ.上のrunの中で
Looper myLooper, mainLooper;
myLooper = Looper.myLooper ();//明らかにこれは空に戻ります.prepareがまだないので、Looperには戻りません.
mainLooper = Looper.getMainLooper ();
 
Looperを読むときは高煥堂の本を読まないことをお勧めします.彼もよく分からないような気がしますが、私を混乱させました.そんなにたくさん話して、完全に彼自身の理解で、彼自身の理解はとても複雑で、肝心なのは簡単な問題を複雑化して、しかも複雑な後のものはやはり間違っています.Goole Music Appのソースコードを見てみましょう.
 
MediaPlayback Activity.JAvaでは、OnCreateの次の2つの文を見てみましょう.
        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 {@link 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の取得が絶対に正しいことを保証することができます.この構想は創意的です.参考に値する.