1、Handler 機制 Android 中主線程也叫 UI 線程,那麼從名字上我們也知道主線程主要是用來創建、更新 UI 的,而其他耗時操作,比如網路訪問,或者文件處理,多媒體處理等都需要在子線程中操作,之所以在子線程中操作是為了保證 UI 的流暢程度,手機顯示的刷新頻率是 60Hz,也就是一秒鐘 ...
1、Handler 機制
Android 中主線程也叫 UI 線程,那麼從名字上我們也知道主線程主要是用來創建、更新 UI 的,而其他耗時操作,比如網路訪問,或者文件處理,多媒體處理等都需要在子線程中操作,之所以在子線程中操作是為了保證 UI 的流暢程度,手機顯示的刷新頻率是 60Hz,也就是一秒鐘刷新 60 次,每16.67 毫秒刷新一次,為了不丟幀,那麼主線程處理代碼最好不要超過 16 毫秒。當子線程處理完數據後,為了防止 UI 處理邏輯的混亂,Android 只允許主線程修改 UI,那麼這時候就需要 Handler來充當子線程和主線程之間的橋梁了。
我們通常將 Handler 聲明在 Activity 中,然後覆寫 Handler 中的 handleMessage 方法,當子線程調用 handler.sendMessage()方法後 handleMessage 方法就會在主線程中執行。這裡面除了 Handler、Message 外還有隱藏的 Looper 和 MessageQueue 對象。在主線程中 Android 預設已經調用了 Looper.preper()方法,調用該方法的目的是在 Looper 中創 建 MessageQueue 成 員 變 量 並 把 Looper對象綁定到當前線程中。 當調用 Handler 的sendMessage(對象)方法的時候就將 Message 對象添加到了 Looper 創建的 MessageQueue隊列中,同時給 Message 指定了 target 對象,其實這個 target 對象就是 Handler 對象。主線程默
認執行了 Looper.looper () 方法, 該方法從 Looper 的成員變數 MessageQueue 中取出 Message,然後調用 Message 的 target 對象的 handleMessage()方法。這樣就完成了整個消息機制。
2、事件分發機制
2.1 事件分發中的 onTouch 和 onTouchEvent 有什麼區別,又該如何使用?
這兩個方法都是在 View 的 dispatchTouchEvent 中調用的,onTouch 優先於 onTouchEvent執行。如果在 onTouch 方法中通過返回 true 將事件消費掉,onTouchEvent 將不會再執行。另外需要註意的是,onTouch 能夠得到執行需要兩個前提條件,第一 mOnTouchListener 的值不能為空,第二當前點擊的控制項必須是 enable 的。因此如果你有一個控制項是非 enable 的,那麼給它註冊 onTouch 事件將永遠得不到執行。對於這一類控制項,如果我們想要監聽它的 touch 事件,就必須通過在該控制項中重寫 onTouchEvent 方法來實現。
2.2 請描述一下 Android 的事件分發機制
Android 的事件分發機制主要是 Touch 事件分發,有兩個主角:ViewGroup 和 View。Activity的 Touch 事件事實上是調用它內部的 ViewGroup 的 Touch 事件,可以直接當成 ViewGroup 處理。View 在 ViewGroup 內, ViewGroup 也可以在其他 ViewGroup 內, 這時候把內部的 ViewGroup當成 View 來分析。
先分析 ViewGroup 的處理流程:首先得有個結構模型概念:ViewGroup 和 View 組成了一棵樹形結構,最頂層為 Activity 的 ViewGroup,下麵有若幹的 ViewGroup 節點,每個節點之下又有若幹的 ViewGroup 節點或者 View 節點,依次類推。如圖:
當一個 Touch 事件(觸摸事件為例)到達根節點,即 Acitivty 的 ViewGroup 時,它會依次下發,下發的過程是調用子 View(ViewGroup)的 dispatchTouchEvent 方法實現的。簡單來說,就是ViewGroup 遍歷它包含著的子 View,調用每個 View 的 dispatchTouchEvent 方法,而當子 View為 ViewGroup 時,又會通過調用 ViwGroup 的 dispatchTouchEvent 方法繼續調用其內部的 View的 dispatchTouchEvent 方法。上述例子中的消息下發順序是這樣的:①-②-⑤-⑥-⑦-③-④。
dispatchTouchEvent 方法只負責事件的分發,它擁有 boolean 類型的返回值,當返回為 true 時,順序下發會中斷。在上述例子中如果⑤的dispatchTouchEvent 返回結果為 true,那麼⑥-⑦-③-④將都接收不到本次 Touch 事件。
1.Touch 事 件 分 發 中 只 有 兩 個 主 角 :ViewGroup 和 View。ViewGroup 包 含onInterceptTouchEvent 、 dispatchTouchEvent、onTouchEvent 三個相關事件。 View包含dispatchTouchEvent、onTouchEvent 兩個相關事件。其中 ViewGroup 又繼承於 View。
2.ViewGroup 和 View 組成了一個樹狀結構,根節點為 Activity 內部包含的一個 ViwGroup。
3.觸摸事件由 Action_Down、Action_Move、Aciton_UP 組成,其中一次完整的觸摸事件中,Down 和 Up 都只有一個,Move 有若幹個,可以為 0 個。
4.當 Acitivty 接收到 Touch 事件時,將遍歷子 View 進行 Down 事件的分發。ViewGroup 的遍歷可以看成是遞歸的。分發的目的是為了找到真正要處理本次完整觸摸事件的 View,這個 View 會在 onTouchuEvent 結果返回 true。
5.當某個子 View 返回 true 時, 會中止 Down 事件的分發, 同時在 ViewGroup 中記錄該子 View。接下去的 Move 和 Up 事件將由該子 View 直接進行處理。 由於子 View 是保存在 ViewGroup 中的,多層 ViewGroup 的節點結構時,上級 ViewGroup 保存的會是真實處理事件的 View 所在的ViewGroup 對象:如 ViewGroup0-ViewGroup1-TextView 的結構中,TextView 返回了 true,它將被保存在 ViewGroup1 中,而 ViewGroup1 也會返回 true,被保存在ViewGroup0 中。當 Move和 UP 事件來時,會先從 ViewGroup0 傳遞至 ViewGroup1,再由 ViewGroup1 傳遞至 TextView。
6.當 ViewGroup 中所有子 View 都不捕獲 Down 事件時,將觸發 ViewGroup 自身的 onTouch事件。觸發的方式是調用 super.dispatchTouchEvent 函數,即父類 View 的 dispatchTouchEvent方法。在所有子 View 都不處理的情況下,觸發 Acitivity 的 onTouchEvent 方法。
7.onInterceptTouchEvent 有兩個作用:1.攔截 Down 事件的分發。2.中止 Up 和 Move 事件向目標 View 傳遞,使得目標 View 所在的 ViewGroup 捕獲 Up 和 Move 事件。
3、子線程發消息到主線程進行更新 UI,除了 handler 和 AsyncTask,還有什麼?
(1)用 Activity 對象的 runOnUiThread 方法更新在子線程中通過 runOnUiThread()方法更新 UI:
(2)用 View.post(Runnable r)方法更新 UI
4、子線程中能不能 new handler?為什麼?
不能,如果在子線程中直接 new Handler()會拋出異常 java.lang.RuntimeException: Can't create handler inside thread that has not called