インタビューはオフにリッピングするように頼まれましたか?ハンドラは、私もインタビュアーよりも劣ら取ることを信じていないあなたはステップの深いソースバイステップで取りませんか?

Androidのハンドラのメカニズムは非常に古典的な非同期メッセージメカニズムである、我々は直接使用シナリオの相当数はまだ、アプリケーション層または層フレームワークに直面しているかどうか、Androidの開発の歴史の中で重要な役割を果たしています。

私はここで多くの友人にインタビューするように求め、そして時には無意味尋ねたところ。綿密ハンドラソースステップで登ると、あなたに一歩を踏み出すためにどこ落ちるところから、また、インタビュアーよりも劣ら取ると信じていません!

BATJ、パフォーマンスの最適化へのバイト鼓動インタビューのトピック、トピックアルゴリズム、ハイエンドの技術のトピック、複合用途の開発テーマ、Javaのインタビューのトピック、アンドロイド、Javaの少しの知識、。.View.OpenCV.NDKスレッドなどは私のGitHubにアップロードされた
あなたはクリック私のGitHubのアドレス:https://github.com/Meng997998/AndroidJXスターポイントの下で一緒に学びます

見つけるためにソースコード解析。

一般的な使用法から言えば:

private Button mBtnTest;
private Handler mTestHandler = new Handler(){
   @Override
   public void handleMessage(Message msg) {
       switch (msg.what){
           case 1:
               mBtnTest.setText("收到消息1");
       }
   }
};
@Override
protected void onCreate(final Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   mBtnTest = (Button) findViewById(R.id.btn_test);
   new Thread(new Runnable() {
       @Override
       public void run() {
           try {
               Thread.sleep(3000);
               mTestHandler.sendEmptyMessage(1);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
   }).start();
}

前本物の作品のさらなる理解のために、我々は最終的な結果荘がどうなるか、最初に彼が何をやっていることを理解することが事の価値観を持っている必要がありますし、次に何をすべきかを理解することや農産物何かが起こります。

私たちは、この研究では、プロセスは、この結果を生成するために通過するために何を、何が起こったかの結果が何であるかを最終的に経験してきたということです議論したいです。

あなたはハンドラに関連するメッセージを送信するメソッドを呼び出すと、これは、どこへ行くにメッセージを送信しますか?もし上記の例のコードからのメッセージは、最終的にハンドラは、自身が取り扱うの手に戻ります見ることができます。私たちは、プロセスによって送信されたメッセージを受信することで知りたいです。

メッセージはどこへ行くに送信されますか?

mTestHandler.sendEmptyMessage(1)。

我々はどこへ行くsendEmptyMessage()メソッドに従います。

ハンドラの方法を送信されたメッセージの種類に関係なく、それはsendMessageAtTime()メソッドを経由します:

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);
}

そして、最初に現在のハンドラのmqueueをオブジェクトを決定します。このメソッドは空で、その後、文字通りの意味から、enqueueMessage()メソッドを呼び出すと、一緒にチームにメッセージを保存することを理解することは難しいことではありません。enqueueMessage()メソッドを探します。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
   msg.target = this;
   if (mAsynchronous) {
       msg.setAsynchronous(true);
   }
   return queue.enqueueMessage(msg, uptimeMillis);
}

public final class Message implements Parcelable {
   //....
   Handler target;
}

直接それがハンドラのメッセージを望んでいるときに対処するために彼の訓練と準備をバインドするときの方法だろう最初のバインドメッセージハンドラと、現在は、それが理解しやすいです。そして、チームに正式にqueue.enqueueMessage()メソッドを呼び出し、そして最後にキューオブジェクトは、どのような種類のオブジェクトのでしょうか?メッセージキューは、単独リンクリストによって実装されています。queue.enqueueMessage()メソッドは、メッセージキューは、メッセージヘッダを取り出すことであるから、テーブルに保存されたメッセージの最後にリストをトラバースすることです。

それから彼が作成された時にキューイングする方法を見つけるには?ハンドラのコンストラクタは、ビューポイント。

public Handler(Callback callback, boolean async) {
   mLooper = Looper.myLooper();
   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;
}

ハンドラのコンストラクタは、最初のプログラムが直接飛び込ん得ることができない場合、私は、ルーパーオブジェクトを得ることができる場合Looper.myLooper()メソッドが参照呼び出します。その後、我々は、キュールーパーオブジェクトからメッセージを取得する必要があります。

最後にルーパーはアイデンティティのこの種を持っているオブジェクトの種類は、どのようにハンドラメカニズムでこの役割を果たしているのですか?ビューmyLooper()メソッド:

public static @Nullable Looper myLooper() {
   return sThreadLocal.get();
}

myLooper()メソッドは、sThreadLocalオブジェクトルーパーから直接利用できるようになり、そしてsThreadLocal白色プライベートスレッドによって彼のストアのオブジェクトであることをThreadLocalのクラス・オブジェクト、およびThreadLocalのクラスです。

静的最終ThreadLocalのsThreadLocal =新しいThreadLocalの()。

コールのThreadLocalから直接ルーパーを取得する()メソッドを取得するために、我々は見ているLoooperにThreadLocalを保存するためのセットは、()に行くようにオブジェクト際れます。Looper.prepare()メソッド:

private static void prepare(boolean quitAllowed) {
   if (sThreadLocal.get() != null) {
       throw new RuntimeException("Only one Looper may be created per thread");
   }
   sThreadLocal.set(new Looper(quitAllowed));
}

private Looper(boolean quitAllowed) {
   mQueue = new MessageQueue(quitAllowed);
   mThread = Thread.currentThread();
}

このソースからわかるように、ルーパ糸はプライベートまたは非交換可能なだけではありません。ルーパーオブジェクトは、私たちがキューに必要なもの、メッセージキュー()オブジェクトが作成されて初期化されます。
理由は、ほとんどのサンプルコード上記の、私たちは、このプログラムはルーパーでの主な方法ActivityThreadでオブジェクトを初期化されているので、それは、クラッシュしない()メソッドは、ルーパーを初期化準備呼び出していませんでした。

public final class ActivityThread {
   //......
   public static void main(String[] args) {
       Looper.prepareMainLooper();
   }
   //......
}

私たちは、このメッセージがどこへ行くに送信されることを理解し、そして今、私たちが知っておくべきメッセージ・ハンドラ・プロセスを取得する方法です。

まず、メッセージキューは、(エンキュー)を添加し、完全なパッケージと取り外さメッセージヘッダのうちの最初のリストのアクセス/削除(デキュー)方法、MessageQueeue.next()メソッド。

Message next() {
   //..........
   for (;;) {
       if (nextPollTimeoutMillis != 0) {
           Binder.flushPendingCommands();
       }

       nativePollOnce(ptr, nextPollTimeoutMillis);

       synchronized (this) {
           final long now = SystemClock.uptimeMillis();
           Message prevMsg = null;
           Message msg = mMessages;
           if (msg != null && msg.target == null) {
               do {
                   prevMsg = msg;
                   msg = msg.next;
               } while (msg != null && !msg.isAsynchronous());
           }
           if (msg != null) {
               if (now < msg.when) {
                   nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
               } else {
                   mBlocked = false;
                   if (prevMsg != null) {
                       prevMsg.next = msg.next;
                   } else {
                       mMessages = msg.next;
                   }
                   msg.next = null;
                   if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                   msg.markInUse();
                   return msg;
               }
           } else {
               nextPollTimeoutMillis = -1;
           }

           if (mQuitting) {
               dispose();
               return null;
           }
           //............
       }
       //..............
   }
}

コードがもっとあるが、我々は、3行39列から開始しなければなりません。next()メソッドは、実際に無限ループであり、電流は常に、それはループの外ではなく、現在のメッセージ・キューが望ましくない場合でも、メッセージキューを選ぶであろうキューがnext()メソッドへのメッセージから取り出すことができるまで、実行されました実行するには、終了します。

第二に、ときルーパーコールはトゥーレ、next()メソッドが返すヌル実行方法が終了するとき、無限ループの外に変数をmQuitting、()メソッドを終了します。

上記メインActivityThreadに()メソッドは、ルーパーを初期化し、実際には、近い将来にキューからメッセージを取り始めます。

public static void main(String[] args) {

   //......
   Looper.prepareMainLooper();

   ActivityThread thread = new ActivityThread();
   thread.attach(false);

   if (sMainThreadHandler == null) {
       sMainThreadHandler = thread.getHandler();
   }

   if (false) {
       Looper.myLooper().setMessageLogging(new
               LogPrinter(Log.DEBUG, "ActivityThread"));
   }

   Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
   Looper.loop();

   throw new RuntimeException("Main thread loop unexpectedly exited");
}

调用Looper.loop()方法就会开始遍历取消息。

public static void loop() {
for (;;) {
   Message msg = queue.next(); // might block
   if (msg == null) {
       return;
   }

   final Printer logging = me.mLogging;
   if (logging != null) {
       logging.println(">>>>> Dispatching to " + msg.target + " " +
               msg.callback + ": " + msg.what);
   }

   final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

   final long traceTag = me.mTraceTag;
   if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
       Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
   }
   final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
   final long end;
   try {
       msg.target.dispatchMessage(msg);
       end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
   } finally {
       if (traceTag != 0) {
           Trace.traceEnd(traceTag);
       }
   }
}

ループ()メソッドは無限ループで、queue.nex()メソッドが起動するメッセージを取るために、ブロッキング呼び出して、これだけ手動ルーパー停止することを、次の()メソッドはnullを返します。

メッセージを処理するDispatchMessageを()メソッドを呼び出して、メッセージを取った後ハンドラをいいます。

msg.target.dispatchMessage(MSG)。

public void dispatchMessage(Message msg) {
   if (msg.callback != null) {
       handleCallback(msg);
   } else {
       if (mCallback != null) {
           if (mCallback.handleMessage(msg)) {
               return;
           }
       }
       handleMessage(msg);
   }
}

だけでなく、コールバックインタフェースを設定することができ、またラインにメッセージハンドラ。コールは、デフォルトでのhandleMessage()メソッドをバックアップ。

私は重要な問題でもあり、右のそれについて考えました。我々ループがメインスレッド()メソッドで実行され、なぜ活動が立ち往生無限ループ障害にはなりませんでしたか?なぜそのnext()メソッドの死後無限ループカードでメインスレッドとは限らないLooper.loop(内の情報へのAndroidのアクセスは)重要な方法を実行します。

nativePollOnce(PTR、nextPollTimeoutMillis)。

ギャングスター分析は非常によく、私はもっと言うことはありません。言及長くやる保存するだけでなく、この方法によって遅延されるとき、遅延は、私たちが送ったメッセージは、メッセージのフィールド/変数を介してであろうと。

Message next() {

   final long now = SystemClock.uptimeMillis();

   if (msg != null) {
       if (now < msg.when) {
           // Next message is not ready.  Set a timeout to wake up when it is ready.
           nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
       } else {
           //......
       }
   }
}

集計保存、ハンドラは行くメッセージキュー、およびルーパーはサイクルがメッセージを取った後、キューからメッセージを取った死んでしまうのメッセージルーパー保守メッセージキューにメッセージを送信するコールバックハンドラメッセージハンドラは、結合と呼ぶことにします。

テキストが十分でない場合、私はソースも顔の質問BAT、私は駅bにアップロードした動画を組み込んだ、説明を説明するためにサムスンの建築家ハンドラの通信メカニズムから、究極の学習攻略、思い付きます:https://www.bilibili.com/video/av78745845

私に友人が、時々からの質問に直面することになる記事を初めて目には、PDF + + +高度なビデオインタビュードキュメントの共有ソースのノートを学ぶだけでなく、メーカー、Androidのアーキテクチャおよびその他の技術的な知識や分析内容を公開します

おすすめ

転載: blog.51cto.com/14606040/2465693