Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Day25-Handler和Application

Day25-Handler和Application

編輯:關於Android編程

Handler

handler是什麼 ?

是android給我們提供用來更新UI的一套機制, 也是一套消息處理的機制, 我們可以發送消息, 也可以通過它處理消息

為什麼要用handler

Android在設計的時候, 就封裝了一套消息創建, 傳遞, 處理機制, 如果不遵循這樣的機制就沒有辦法更新UI信息, 就會拋出一異常信息

handler怎麼用 ?

文檔表述:
A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it – from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

android為什麼要設計只能通過Handler機制更新UI ?

最根本的原因是解決多線程並發問題.
假設如果在一個Activity當中, 有多個線程去更新UI, 並且都沒有加鎖機制, , 那麼會產生什麼樣的現象呢 ?

更新界面錯亂 !

如果對更新UI的操作都進行加鎖處理的話又會產生什麼樣的問題呢

性能下降!!!!!

處於對以上目的問題的考慮, android給我們一套更新Ui的機制, 我們只需要遵循這樣的機制就可以了,
根本不用關心多線程的問題, 所以更新UI的操作, 都是在主線程的消息隊列當中去輪詢處理的

Handler原理是什麼 ?

面試重要!!!!!

Handler封裝了消息的發送 (主要包括把消息發送給誰)

Android中對應 “生產者和消費者” 模型

Message : 產品
MessageQueue : 倉庫 (永遠用不到, Android已封裝好)
Looper : 循環
Handler : 對倉庫和循環的一個持有 (通過Handler放置產品) [類似物流]
Handler.Callback 回調接口, 必須自己去實現

Looper

1, 內部包含一個消息隊列也就是MessageQueue, 所有的Handler發送的消息都走向這個消息隊列

2, Looper.looper方法, 就是一個死循環, 不斷的從MessageQueue去取消息, 如果有消息就處理消息, 沒有消息就阻塞

3, 一個線程可以產生一個Looper對象,由它來管理此線程裡的MessageQueue(消息隊列)。

MessageQueue

就是一個消息隊列, 可以添加消息, 並處理消息

Handler

內部會跟Looper進行關聯, 也就是說Handler的內部可以找到Looper, 找到了Looper也就找到了, MessageQueue , 在Handler中發送消息, 其實就是向MessageQueue隊列中發送消息

UIthread 通常就是main thread,而Android啟動程序時會替它建立一個MessageQueue。

總結:

handler負責發送消息, Looper負責接收Handler發送的消息, 並直接把消息回傳給handler自己, MessageQueue就是一個存儲消息的容器

對Looper和Looper.loop的深入理解

Android中的Looper類,是用來封裝消息循環和消息隊列的一個類,用於在android線程中進行消息處理。handler其實可以看做是一個工具類,用來向消息隊列中插入消息的。

(1) Looper類用來為一個線程開啟一個消息循環。 默認情況下android中新誕生的線程是沒有開啟消息循環的。(主線程除外,主線程系統會自動為其創建Looper對象,開啟消息循環。) Looper對象通過MessageQueue來存放消息和事件。一個線程只能有一個Looper,對應一個MessageQueue。

(2) 通常是通過Handler對象來與Looper進行交互的。Handler可看做是Looper的一個接口,用來向指定的Looper發送消息及定義處理 方法。 默認情況下Handler會與其被定義時所在線程的Looper綁定,比如,Handler在主線程中定義,那麼它是與主線程的Looper綁定。 mainHandler = new Handler() 等價於new Handler(Looper.myLooper()). Looper.myLooper():獲取當前進程的looper對象,類似的 Looper.getMainLooper() 用於獲取主線程的Looper對象。

(3) 在非主線程中直接new Handler() 會報如下的錯誤: E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception E/AndroidRuntime( 6173): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare() 原因是非主線程中默認沒有創建Looper對象,需要先調用Looper.prepare()啟用Looper。

(4) Looper.loop(); 讓Looper開始工作,從消息隊列裡取消息,處理消息。

注意:寫在Looper.loop()之後的代碼不會被執行,這個函數內部應該是一個循環,當調用mHandler.getLooper().quit()後,loop才會中止,其後的代碼才能得以運行。

感謝原作者

Handler機制運行過程

以上是對Handler整個運行機制內部的詳細描述, 有興趣的同學可以查看一下源碼

Handler創建消息

每一個消息都需要被指定的Handler處理,通過Handler創建消息便可以完成此功能。Android消息機制中引入了消息池。Handler創建消息時首先查詢消息池中是否有消息存在,如果有直接從消息池中取得,如果沒有則重新初始化一個消息實例。使用消息池的好處是:消息不被使用時,並不作為垃圾回收,而是放入消息池,可供下次Handler創建消息時使用。消息池提高了消息對象的復用,減少系統垃圾回收的次數。消息的創建流程如圖所示。

這裡寫圖片描述

//推薦使用, Message中有一個消息池, 會循環使用內部的message
Message message = Message.obtain();
Message obtain = Message.obtain(handler, 0, String.valueOf(i + 1))
Message.obtain(handler);
handler.obtainMessage()

Handler發送消息

UI主線程初始化第一個Handler時會通過ThreadLocal創建一個Looper,該Looper與UI主線程一一對應。使用ThreadLocal的目的是保證每一個線程只創建唯一一個Looper。之後其他Handler初始化的時候直接獲取第一個Handler創建的Looper。Looper初始化的時候會創建一個消息隊列MessageQueue。至此,主線程、消息循環、消息隊列之間的關系是1:1:1。

Handler、Looper、MessageQueue的初始化流程如圖所示:
這裡寫圖片描述

Hander持有對UI主線程消息隊列MessageQueue和消息循環Looper的引用,子線程可以通過Handler將消息發送到UI線程的消息隊列MessageQueue中

handler.sendMessage(message);
//在有Handler對象的前提下調用
message.sendToTarget();

處理消息

UI主線程通過Looper循環查詢消息隊列UI_MQ,當發現有消息存在時會將消息從消息隊列中取出。首先分析消息,通過消息的參數判斷該消息對應的Handler,然後將消息分發到指定的Handler進行處理。

子線程通過Handler、Looper與UI主線程通信的流程如圖所示。

這裡寫圖片描述

// 臨時解決方案, 如果代碼規范的話不會出現下面的情況
 Message obtain = Message.obtain(handler, new Runnable() {
     @Override
     public void run() {
         //可以在這個方法中執行UI操作
     }
 });
 //不會調用handler中的handleMessage, 而是調用上面的run方法
 handler.sendMessage(obtain);
 handler.post(new Runnable() {
     @Override
     public void run() {

     }
 });
 runOnUiThread(new Runnable() {
     @Override
     public void run() {

     }
 });

感謝原作者

Application

只要在一個應用中, 所有的Activity共用一個Application, 保存一些全局的變量

注意: 所有的應用被銷毀的時候, Application不一定被銷毀無論怎麼用, Application只會創建一次

如何創建一個自己的Application

BaseApplication.java

public class BaseApplication extends Application {
    private static final String TAG = BaseApplication.class.getSimpleName();
    private String text;

    /**
     * 啟動時, 只執行一次, 做應用的初始化
     */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
        text = "BaseApplication";

    }


    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

在清單文件中添加


在MainActivity中獲取創建的Application

private static final String TAG = MainActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(TAG, "onCreate: ");
    setContentView(R.layout.activity_main);
    BaseApplication application = (BaseApplication) getApplication();
    String text = application.getText();
    Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
    application.setText("啟動一次後");
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved