Androidソース分析-メッセージの列とLooper

9444 ワード

転載は出典を明記してください.http://blog.csdn.net/singwhatiwanna/article/details/17361775
前言
先週はAndroidのイベント配信の仕組みを分析しましたが、今回のブログでは主にニュースキューとLooperのソースコードを簡単に分析しています.皆さんは辛抱強く見ていますが、実際にはニュースの行列の論理は事件の配布メカニズムより簡単になりましたので、皆さんは分かりやすいと思います.
概念
1.メッセージキューとは?
メッセージ・キューは、androidでMessage Queというクラスに対応しています.名前の通り、メッセージ・キューには多くのメッセージが格納されています.
2.何がニュースですか
メッセージ(Message)は、一つの行為(what)または一連の動作(Runnable)を表し、二つの場所がMessage:HandlerとMessengerを使用します.
3.何がHandlerとMessengerですか?
Handlerはみんな知っています.主にスレッドの中でメッセージを送るために、uiスレッドの更新をお知らせします.Messengerはメッセンジャーに翻訳でき、プロセス間通信(IPC)が可能であり、Messengerは単一のプログラムですべてのメッセージを処理しています.そしてプロセス間の通信はすべてメッセージで行われています.AIDLのように直接に相手のインターフェース方法を呼び出すことができないと感じています.これはAIDLとの主な違いです.つまりMessengerはマルチスレッドを扱うことができず、すべての呼び出しは同じスレッドの中でシリアルで実行されます.Messengerの典型的なコードは、new Messenger.service.send(msg)であり、その本質はやはりHandlerのsendMessageメソッドを呼び出しています.
4.ループとは
Looperはループという意味で、メッセージ・キューから循環的にメッセージを取り出して目的に渡すことを担当しています.
5.スレッドにはLooperの違いがありますか?
スレッドにLooperがないとメッセージキューがないので、メッセージを処理できません.スレッド内部ではHandlerは使えません.これはなぜ、スレッド内部にHandlerを作成するとエラーが発生するのですか?「Can't create hander inside thread has not caled Looper.prepare()」という具体的な原因を分析します.
6.スレッドにループがあるようにして、Handlerを正常に使うにはどうすればいいですか?
スレッドのrun方法には、次の2つの文が加えられています.
Looper.prepare()
Looper.loop()
このすべては私達がしなくてもいいです.既製品があります.HandlerThreadはLooperのスレッドがあります.
スレッドのLooperを使ってHandlerを作成したいです.簡単です.Handler handler=new Handler(thread.get Looper).上のステップがあれば、子スレッドの中でHandlerを作成できます.いいですよね.実はandroidはとっくに私達のためにこの点を考えています.自分で書かなくてもいいです.IntentServiceは私達のものを使ってください.具体的にはどうやって後ろで話しますか?
メッセージキューとLooperの作業メカニズム
一つのHandlerにはLooperがあります.一つのLooperにはメッセージのキューがあります.Looperの役割は循環的にメッセージのキューを巡回することです.新しいメッセージがあれば、新しいメッセージをその目標に処理します.メッセージをHandlerで送信するたびに、メッセージはメッセージキューに入れられ、次にLooperはメッセージを取り出してそのターゲットtargetに送信する.一般的には、メッセージのtargetはこのメッセージを送るHandlerであり、これによってLooperはHandlerにメッセージを渡します.この時はHandlerのdispatch Message方法が呼び出されます.一般的には最終的にHandlerのhandleMessageを呼び出してメッセージを処理します.
ソース分析
1.Handlerメッセージ送信プロセス
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
	
	public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
	
	public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
		MessageQueue queue = mQueue;
		if (queue == null) {
			RuntimeException e = new RuntimeException(
					this + " sendMessageAtTime() called with no mQueue");
			Log.w("Looper", e.getMessage(), e);
			return false;
		}
		return enqueueMessage(queue, msg, uptimeMillis);
	}
	
	private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //  msg       queue
        return queue.enqueueMessage(msg, uptimeMillis);
    }
2.Looperの作業過程
   public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        // Looper       
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        //   ,      ,         
        for (;;) {
            Message msg = queue.next(); // might block       ,       
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            //     target  ,  target  Handler  
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycle();
        }
    }
3.Handlerはどうやってメッセージを処理しますか?
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            //       ,    msg.callback.run();
            handleCallback(msg);
        } else {
            //       callback  callback     
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //           ,            
            handleMessage(msg);
        }
    }
もう一度msg.callbackとmCallbackは何ですか?
//package*/Runnable calback;
今はもうはっきりしました.msg.calbackはRunnableです.いつこのcalbackを設置しますか?handler.post(runnable).みなさんはこの方法をよく使うと思います.
 /**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
public interface Callback {
	public boolean handleMessage(Message msg);
}
	
final Callback mCallback;
mcallbackはインターフェイスです.このようにHandler handler=new Handlerをセットしてもいいです.このcalbackの意味は何ですか?コードのコメントはもう言っています.Handlerのサブクラスを作成しなくてもいいですが、そのままメッセージを処理してもいいです.おそらく皆さんがよく使うのは新しいnewのHandler一つのHandlerで、そしてoverride handledle Medle Medlessage Medlessageです.これからは、Handlerのサブクラスを作成しなくても、メッセージを処理できることを知っています.もっと言ってください.なぜハードラーのサブクラスを作るのがよくないですか?これは、クラスもスペースを占めています.一つのアプリケーションのクラスが多すぎて、その占有空間が大きくなります.つまり、応用はメモリを消費します.
HandlerThread概要
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
HandlerThreadはThreadから継承されています.runメソッドの内部にLooperを作成しました.HandlerThreadは普通のThreadと違って、よくあるバックグラウンド操作ができなくて、新しいメッセージを処理するしかないです.これはLooper.loop()が死のサイクルです.あなたのコードはまったく実行できません.でも、前にコードを置くことができます.しかし、これは主流の遊び方ではないようですので、このようにすることは勧められません.
IntentService概要
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
IntentServiceはServiceから継承された抽象的なクラスであり、作成された時にnewになりました.HandlerThreadとServiceHandlerがあります.これがあれば、IntentServiceを利用して優先度の高いtaskを行うことができます.IntentServiceはシステムに簡単に殺されません.IntentServiceを使うのも簡単です.まずstartServiceを利用して、IntentServiceがあなたのintentをMessageにパッケージしてServiceHandlerを通じて送信します.そしてServiceHandlerはone HandleIntentを呼び出してこのMessageを処理します.今必要なのは、IntentServiceから派生したサブクラスで、onhandleIntentメソッドを書き直して、異なるintentに対して異なることをすればいいです.仕事が終わったら、IntentServiceは自動的に停止します.したがって、IntentServiceは、ThreadとAyncTaskの他に、時間のかかる操作を行う方法であり、システムによって容易にやられないため、キー操作はIntentServiceを採用することを提案しています.
子スレッドでHandlerを作成しましたが、なぜエラーが発生しましたか?
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        //       Looper
        mLooper = Looper.myLooper();
        //        :      Looper
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
はどのようにこのようなエラーを回避しますか?