<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                在Android中,有一個規定就是除了主線程,其他線程不能操作UI視圖,因為不這樣做的話會出現線程不安全問題。但還有一個規定UI線程在執行一個操作如果5秒內沒有響應就會包ANR錯誤。所以UI線程中不允許訪問網絡這樣的耗時操作,那么問題來了,子線程執行耗時操作,比如從網絡獲取圖片,但子線程不能更新UI,而主線程能更新UI,但不能去下載圖片。這樣handler消息處理機制就出現了。 ### 1. Handler是什么? handler是Android給我們提供用來更新UI的一套機制,也是一套消息處理的機制,我們可以發送消息,也可以通過它處理消息。 ### 2. 為什么要使用Handler? Android在設計時,就封裝了一套消息消息創建、傳遞、處理機制,如果不遵循這樣的機制就沒辦法更新UI,就會拋出異常。 ### 3. Android中為什么要設計只能通過Handler機制更新UI? 解決多線程并發問題。如果允許多線程更新UI會導致界面錯亂,如果非要使用多線程并使用加鎖機制更新UI又會導致性能下降,所以更新UI的操作全部交給主線程。 ### 4.那么handler機制是怎樣的機制呢? 了解handler機制,首先需要清楚四個核心類: **Message:**對發送的消息的封裝 **MessageQueue:**消息隊列,存放所有的消息 **Looper:**可以循環讀取消息(從MessageQueue中讀取) **Handler:**處理消息,同時也是發送消息的 **具體來看看handler是怎么實現的。** 4.1使用1:主線程接收子線程發來的消息(下載圖片為例) 1)在主線程中初始化handler對象: ~~~ private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { //處理子線程發送過來的message Bitmap bitmap = (Bitmap)msg.obj; imageView.setImageBitmap(bitmap); } }; ~~~ 2)然后子線程中下載好圖片后發送圖片給主線程: ~~~ new Thread(new Runnable() { @Override public void run() { HttpGet get = new HttpGet(path); HttpClient client = new DefaultHttpClient(); HttpResponse response = null; try { response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { byte[] arr = EntityUtils.toByteArray(response .getEntity()); Bitmap bitmap = BitmapFactory.decodeByteArray(arr, 0, arr.length); // 下載完成時把圖片發送給主線程 // 從MessageQueue中獲取可用的Message對象,如果沒有可用的Message對象則會創建一個新的Message對象 Message msg = Message.obtain(); // 把發送的圖片封裝到msg中 msg.obj = bitmap; // 使用Handler發送msg handler.sendMessage(msg);// 把msg發送給實例化handler的線程 } } catch (Exception e) { e.printStackTrace(); } } }).start(); ~~~ 消息的攔截: ~~~ /** * 攔截消息測試 * @author Administrator * */ public class ThirdActivity extends Activity { Handler handler = new Handler(new Callback() { @Override public boolean handleMessage(Message msg) { Log.i("--", "消息都要經過我這里"); /**返回false,消息會繼續向下分發,返回true則攔截*/ return true; } }) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.i("--", "我才是處理消息的"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { handler.sendEmptyMessage(1); } }).start(); } } ~~~ 3)使用1有關handler機制的操作有: Handler handler = new Handler(); handleMessage(Message msg); Message msg = Message.obtain(); handler.sendMessage(msg); 那么現在來看一看它內部到底是怎樣執行的。 ### 5.從源碼一步一步分析handler原理 **5.1Handler handler = new Handler();** ~~~ public Handler() { this(null, false); } ~~~ **這個無參構造方法會調用兩個參數的構造方法,注意上面的參數null和false,如下:** ~~~ 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()); } } 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; } ~~~ **那來看看這個兩個參數的構造方法都做了些什么。** FIND_POTENTIAL_LEAKS這個變量初始化為false private static final boolean FIND_POTENTIAL_LEAKS = false; **所以直接執行后面的,也就是這些:** ~~~ 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對象和一個MessageQueue對象,mLooper = Looper.myLooper();中Looper.myLooper()方法中是得到當前線程的Looper對象。那么當前線程是什么?在這里,因為我們是在主線程中實例化Handler對象,所以當前線程就是主線程,值得注意的是,主線程在創建時就會維護一個Looper對象和MessageQueue對象,所以這里得到的Looper對象和消息隊列都是主線程的。** ~~~ public static Looper myLooper() { return sThreadLocal.get(); } ~~~ **mQueue = mLooper.mQueue;這句說明handler內部的MessageQueue和Looper的MessageQueue是一個。** **好,那么handler的初始化階段先到這里。** **5.2 Message msg = Message.obtain()**; 再來看看這句做了哪些事, **注意:有時候我們會直接這么寫Message msg = new Message();** ~~~ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); } ~~~ **這里的意思就是如果sPool不為空就返回sPool,否則就new一個新的Message對象。(sPool是回收放在消息池中的對象)** ~~~ public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } ~~~ **5.3 handler.sendMessage(msg);** 關鍵的一句終于到了,來看看這個又做了什么。 **第一步:** ~~~ 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); } return queue.enqueueMessage(msg, uptimeMillis); } ~~~ 到第四步算是找到能辦事的了,看這里都辦了哪些事。 **1) msg.target = this;可以查看Message源碼target就是Handler類型的,這里把msg的target指向this,也就是這個發送消息的handler。** **2)queue.enqueueMessage(msg, uptimeMillis);調用queue的enqueueMessage方法,去MessageQueue類中看看。** ~~~ final boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null) { throw new AndroidRuntimeException("Message must have a target."); } boolean needWake; synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } msg.when = when; Message p = mMessages; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } } if (needWake) { nativeWake(mPtr); } return true; } ~~~ **很簡單,就是把handler發送的msg加入到消息隊列中。** **5.4handleMessage(Message msg);** 好了,最后只用處理msg了。這是個回調方法,所以必須要等到Looper去從消息隊列中讀取消息時才會執行。 那就去看看**Looper.loop();**這個循環讀取消息的方法。 ~~~ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } 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); } 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(); } } ~~~ 開頭幾句是得到當前線程的Looper對象,然后同構Looper對象得到queue對象,很明顯,5.1已經說了,那么這里得到的就是主線程那個Looper和MessageQueue。然后開始了死循環,一直從消息隊列中讀取消息,讀不到就返回,否則執行后面操作。注意看后面操作,真正處理消息的時候到了。 **msg.target.dispatchMessage(msg);關鍵就是這句。 它調用了msg的target的dispatchMessage方法,之前說了,target就是發送消息的那個handler,好,再會Handler類看dispatchMessage方法。** ~~~ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } ~~~ **很簡單,這就是一個消息分發處理嘛。**記得handler發送消息有兩種方式,一種就是普通的handler.sendMessage(msg);方法,還有一種就是 ~~~ handler.post(new Runnable(){ @Override public void run() { //主線程應該執行的操作 } }); ~~~ 先來看第一種:直接回調hanleMessage(msg);方法,這樣主程序中就執行該操作啦。 再來看第二種: ~~~ private static void handleCallback(Message message) { message.callback.run(); } ~~~ 調用message.callback的run方法。 從源碼可以一步一步看出,如下,message的callback指向handler調用post方法傳入的Runnable對象。 ~~~ private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } ~~~ 再回頭看dispatchMessage方法,會調用下面這個方法: ~~~ private static void handleCallback(Message message) { message.callback.run(); } ~~~ 內部最后調用run方法。 handler原理基本就這樣了。 **總結:handler對象定義在需要接收本線程或其他線程發送消息的線程中,該線程會維護一個Looper對象和MessageQueue對象,在其他線程或本線程通過handler發送的消息會加入到handler所在線程中的消息隊列中,同時Looper的loop()方法會一直讀取消息隊列,讀到消息后,又讓發送消息的handler處理這個消息。** ### [源碼下載](http://download.csdn.net/detail/u011102153/9116179)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看