Handler 原理分析和使用(二)

来源:http://www.cnblogs.com/ouyanliu/archive/2016/08/05/5738962.html
-Advertisement-
Play Games

在上篇 Handler 原理分析和使用(一)中,介紹了一個使用Handler的一個簡單而又常見的例子,這裡還有一個例子,當然和上一篇的例子截然不同,也是比較常見的,實例如下。 實際運行這個例子,點擊Button之後,TextView文字內容會變成“I get Post Message”。為什麼會是這 ...


在上篇 Handler 原理分析和使用(一)中,介紹了一個使用Handler的一個簡單而又常見的例子,這裡還有一個例子,當然和上一篇的例子截然不同,也是比較常見的,實例如下。

 1 import android.os.Handler;
 2 import android.os.Looper;
 3 import android.os.Message;
 4 import android.os.MessageQueue;
 5 import android.support.v7.app.AppCompatActivity;
 6 import android.os.Bundle;
 7 import android.view.View;
 8 import android.widget.Button;
 9 import android.widget.TextView;
10 
11 public class MainActivity extends AppCompatActivity implements View.OnClickListener{
12 
13     private TextView myTextView;
14     private Button myButton;
15     private Handler myHandler;
16     @Override
17     protected void onCreate(Bundle savedInstanceState) {
18         super.onCreate(savedInstanceState);
19         setContentView(R.layout.activity_main);
20         myHandler = new Handler();
21         myTextView = (TextView)this.findViewById(R.id.text_view);
22         myButton = (Button)this.findViewById(R.id.post);
23         myButton.setOnClickListener(this);
24     }
25 
26     @Override
27     public void onClick(View view) {
28         int id = view.getId();
29         if(id == R.id.post){
30             Runnable updateUI = new Runnable() {
31                 @Override
32                 public void run() {
33                     myTextView.setText("I get Post Message");
34                 }
35             };
36             //將該線程發送到主線程運行
37             myHandler.post(updateUI);
38         }
39     }
40 }

實際運行這個例子,點擊Button之後,TextView文字內容會變成“I get Post Message”。為什麼會是這樣,我們從源碼開始著手查看。

先看Handler的post(Runnable)方法(post還有幾個姊妹方法,這裡不再一一論述,都是殊途同歸)。源碼如下:

1 public final boolean post(Runnable r)
2 {
3   return sendMessageDelayed(getPostMessage(r), 0);
4 }

調用了sendMessageDelayed(...), 先看getPostMessage(r),源碼如下:

1 private static Message getPostMessage(Runnable r) {
2   //獲取消息池中的一個消息
3   Message m = Message.obtain();
4   //將Runnable作為消息的callback
5   m.callback = r;
6   return m;
7  }

在看sendMessageDelayed(Message,int)的源碼:(在Handler 原理分析和使用(一)中有說明)

 1 public final boolean sendMessageDelayed(Message msg, long delayMillis)  
 2    {  
 3        if (delayMillis < 0) {  
 4            delayMillis = 0;  
 5        }  
 6        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
 7  } 
 8 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
 9        MessageQueue queue = mQueue;  
10        if (queue == null) {  
11            RuntimeException e = new RuntimeException(  
12                    this + " sendMessageAtTime() called with no mQueue");  
13            Log.w("Looper", e.getMessage(), e);  
14            return false;  
15        }  
16        return enqueueMessage(queue, msg, uptimeMillis);  
17 } 
18 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
19        //綁定Handler  
20        msg.target = this;  
21        if (mAsynchronous) {  
22            msg.setAsynchronous(true);  
23        }  
24        //將Message推入MessageQueue
25        return queue.enqueueMessage(msg, uptimeMillis);  
26 }

實際上和sendMessage(Message)一樣的流程。當然了緊接著Looper.loop()。然後調用到dispatchMessage(Message) 該方法需要在此重新說明。看源碼:

 1 public void dispatchMessage(Message msg) {  
 2         if (msg.callback != null) {  
 3             //如果message的callback不為空,則
 4             handleCallback(msg);  
 5         } else {  
 6             
 7             if (mCallback != null) {  
 8                  //如果Handler的callback不為空,則
 9                 if (mCallback.handleMessage(msg)) {  
10                     return;  
11                 }  
12             }  
13             //處理Message
14             handleMessage(msg);  
15         }  
16   } 

在進入handleCallback(Message)方法查看源碼:

1 private static void handleCallback(Message message) {
2   //直接執行run方法
3   message.callback.run();
4 }

註意,此時message已經是主線程對象。因此調用run方法就是在主線程中運行。

此外還需要註意,runnable要處理的內容會在主線程中處理,因此不能夠占用太多的時間,從而造成ANR。

 

--------------------------------------------------------------------------------------------

之所以用一條線隔開,是因為還有一個實例需要說明。請註意dispatchMessage(message)裡面的這段代碼:

 if (mCallback != null) {  
         //如果Handler的callback不為空,則
        if (mCallback.handleMessage(msg)) {  
            return;  
      }  
} 

這個mCallback是從哪裡來,這個有引出Handler的另一個使用方法。

首先來看Handler的初始化方法,有一下幾個:

1. publicHandler()

2. publicHandler(Callback)

3. publicHandler(Looper)

4. publicHandler(Looper, Callback) 

第1,3個一眼看去就明白。第4個只要明白第2個也就通了。

關鍵點,Callback是什麼?是一個介面。源碼如下:

1 public interface Callback {
2   public boolean handleMessage(Message msg);
3 }

該介面實際上是要求實現handleMessage(Message)方法,相信這個方法大家都不陌生。

再看該初始化方法:

1 Handler handler = new Handler(new Handler.Callback() {
2         @Override
3         public boolean handleMessage(Message msg) {
4             return false;
5         }
6 });

這裡已經很明顯了。就是重新定義了handleMessage方法。那麼在dispatchMessage方法中如果發現mCallback不為空,則所有的消息都執行該Callback定義的handleMessage(Message).

 

具體的例子不想寫了。今天就到這裡吧。太累了。明天不在深入,而是擴展。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在講解如何選取文檔元素之前,先普及一下什麼是文檔節點: HTML文檔的每個節點都表示一個Node對象,節點樹形結構的根部是Document節點,代表整個文檔,代表HTML元素的節點是Element節點,代表文本的節點是Text節點;Document、Element、Text類都是Node類的子類;( ...
  • 1.HTML基本結構 <!DOCTYPE html> <!DOCTYPE> 聲明位於文檔中的最前面的位置,處於 <html> 標簽之前。此標簽可告知瀏覽器文檔使用哪種 HTML 或 XHTML 規範。 <html> 定義整個HTML文件的內容;所有HTML標簽都應該放到這裡面。 <head> 定義H ...
  • 【1】0,NaN,“”,null,undefined,false的比較;【2】更換字元串中指定的字元;【3】對象的索引(屬性名)為數字時的註意事項 ...
  • 前言 今天項目中做一個圖片效果展示,需要實時從後臺獲取圖片數據,前段做展示。想想用到隊列,比較好實現這個功能,只需要展示隊列里的數據就可以了。於是寫了個js 對列. js code 如果我們傳入 參數就會設置 隊列的大小,不設置隊列無窮大小 測試 不初始化隊列大小 //初始化沒有參數的隊列 var ...
  • <form>表單 name 表單的名稱 action 表單的提交地址 target 打開方式 enctype MIME類型 method 表單數據提交方式,get:在url地址上面傳送參數到伺服器,post:在後臺傳送參數到伺服器 <label> label元素不會向用戶呈現任何特殊效果,不過它為鼠 ...
  • For迴圈九九乘法表 for迴圈是javascript中一種常用的迴圈語句,可以很好的解決在程式中需要重覆執行某些語句,利用for迴圈實現簡單的“九九乘法表”的效果: 讓迴圈從小到大,依次排序,並計算每次的結果,並用 table 使之排列出來。 代碼很少,相對很簡單,也都是基礎,通過簡單的迴圈實現這 ...
  • jquery學習筆記 1.環境搭建 進入官方網站獲取最新的版本 http://jquery.com/download/ ,這裡需要註意 jQuery 分 2 個系列版本 1.x 與 2.x,主要的區別 在於 2.x 不再相容 IE6、7、8 為移動端而優化,由於減少了一些代碼,使得該版本比 jQue ...
  • 一,效果圖。 二,工程圖。 三,代碼。 RootViewController.h RootViewController.m ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...