最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android Handler 機制原理解析

 更新時間:2025年10月20日 14:51:58   作者:木易 士心  
Handler機制是Android系統(tǒng)中實現(xiàn)**線程間通信(Inter-thread Communication)**的核心機制,尤其廣泛用于將子線程中的任務結果傳遞回主線程(UI線程)進行更新操作,本文給大家介紹Android Handler 機制原理詳解,感興趣的朋友跟隨小編一起看看吧

一、 概述

Handler 機制是 Android 系統(tǒng)中實現(xiàn)**線程間通信(Inter-thread Communication)**的核心機制,尤其廣泛用于將子線程中的任務結果傳遞回主線程(UI線程)進行更新操作。其底層基于 消息隊列(MessageQueue)循環(huán)器(Looper) 構建,形成一個典型的生產者-消費者模型。

該機制的核心目標是:

  • 實現(xiàn)跨線程的消息傳遞
  • 避免多線程并發(fā)修改 UI
  • 提供延遲執(zhí)行和定時任務的能力
  • 支持異步任務調度與回調處理

二、 核心組件

1. Handler(處理器)

Handler 是開發(fā)者最常接觸的類,負責:

  • 發(fā)送消息:sendMessage()、post() 等方法
  • 處理消息:通過重寫 handleMessage(Message msg) 或設置 Callback
  • 與特定線程的 LooperMessageQueue 綁定

?? 每個 Handler 必須關聯(lián)一個 Looper,否則會拋出異常。

// 示例:創(chuàng)建 Handler 并綁定當前線程的 Looper
Handler handler = new Handler(Looper.myLooper()) {
    @Override
    public void handleMessage(@NonNull Message msg) {
        // 在指定線程中處理消息
    }
};

2. MessageQueue(消息隊列)

MessageQueue 是一個按時間排序的消息隊列,內部使用單向鏈表結構存儲待處理的消息。

主要職責:

  • 存儲由 Handler 發(fā)送的 Message
  • Message.when(執(zhí)行時間戳)排序插入
  • 提供 next() 方法供 Looper 取出下一條可執(zhí)行消息
  • 支持阻塞等待(無消息時休眠,有消息時喚醒)

?? MessageQueue 并非傳統(tǒng) FIFO 隊列,而是根據執(zhí)行時間排序的優(yōu)先隊列。

3. Looper(循環(huán)器)

Looper 是消息循環(huán)的驅動者,每個線程最多只能有一個 Looper。

關鍵功能:

  • 調用 Looper.prepare() 初始化當前線程的 Looper
  • 調用 Looper.loop() 啟動無限循環(huán),不斷從 MessageQueue 取出消息并分發(fā)
  • 使用 ThreadLocal 保證線程局部性
// 主線程中系統(tǒng)自動調用
Looper.prepareMainLooper(); // 初始化主線程 Looper
...
Looper.loop(); // 開始循環(huán)

4. Message(消息)

Message 是消息的載體,包含以下核心字段:

字段說明
what用戶自定義消息類型
arg1, arg2整型參數,用于傳遞簡單數據
obj任意對象(注意內存泄漏風險)
target目標 Handler,由 Handler.sendMessage() 自動設置
callback如果是 post(Runnable),則 Runnable 封裝為 callback
when消息應被執(zhí)行的時間戳(毫秒)
next指向鏈表中的下一個 Message

推薦使用 Message.obtain() 獲取實例,避免頻繁創(chuàng)建對象。

三、工作原理

1. 整體流程圖

2. 詳細執(zhí)行過程

1. 初始化 Looper(子線程示例)

在非主線程中若要使用 Handler,必須手動創(chuàng)建 Looper。

class WorkerThread extends Thread {
    public Handler handler;
    @Override
    public void run() {
        Looper.prepare(); // 創(chuàng)建當前線程的 Looper 和 MessageQueue
        handler = new Handler(Looper.myLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                switch (msg.what) {
                    case 1:
                        Log.d("Handler", "收到消息: " + msg.obj);
                        break;
                }
            }
        };
        Looper.loop(); // 開始無限循環(huán)讀取消息
    }
    public void quit() {
        if (handler != null) {
            handler.getLooper().quit(); // 安全退出循環(huán)
        }
    }
}

?? 注意:

  • Looper.prepare() 只能調用一次,否則拋出 RuntimeException
  • Looper.loop() 是阻塞方法,直到調用 quit() 才退出

2. 消息發(fā)送機制

Handler 提供多種發(fā)送消息的方式:

方法說明
sendEmptyMessage(int what)發(fā)送空消息
sendMessage(Message msg)發(fā)送自定義消息
post(Runnable r)發(fā)送 Runnable 任務
sendEmptyMessageDelayed(what, delay)延遲發(fā)送
postDelayed(Runnable r, long delayMillis)延遲執(zhí)行 Runnable

底層均調用 enqueueMessage() 將消息插入 MessageQueue。

// 示例:多種發(fā)送方式
handler.sendEmptyMessage(1);
Message msg = Message.obtain();
msg.what = 2;
msg.obj = "Hello";
handler.sendMessage(msg);
handler.post(() -> {
    Log.d("Handler", "Runnable 執(zhí)行");
});
handler.postDelayed(() -> {
    Log.d("Handler", "1秒后執(zhí)行");
}, 1000);

3. 消息處理流程

Handler.dispatchMessage() 是消息分發(fā)的核心邏輯:

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        // 優(yōu)先處理 post(Runnable) 類型的消息
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            // 其次交給 Handler 的 Callback 處理
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 最終調用 handleMessage
        handleMessage(msg);
    }
}
private void handleCallback(Message message) {
    message.callback.run(); // 直接執(zhí)行 Runnable
}

執(zhí)行順序:Runnable > Callback > handleMessage

四、源碼分析(精簡版)

1. Looper 核心實現(xiàn)

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
    final MessageQueue mQueue;
    final Thread mThread;
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    // 準備 Looper
    public static void prepare() {
        prepare(true);
    }
    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));
    }
    // 獲取當前線程的 Looper
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    // 消息循環(huán)主方法
    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;
        for (;;) {
            Message msg = queue.next(); // 可能阻塞
            if (msg == null) return; // 退出循環(huán)
            // 分發(fā)消息
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                // 空實現(xiàn),預留鉤子
            }
            msg.recycleUnchecked(); // 回收消息
        }
    }
}

?? 關鍵點:

  • ThreadLocal 保證每個線程獨享一個 Looper
  • loop() 是死循環(huán),通過 queue.next() 阻塞等待消息
  • msg.target 即發(fā)送該消息的 Handler

2. MessageQueue 關鍵方法

enqueueMessage()—— 入隊

boolean enqueueMessage(Message msg, long when) {
    synchronized (this) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        final long now = SystemClock.uptimeMillis();
        msg.when = when;
        Message p = mMessages; // 鏈表頭節(jié)點
        if (p == null || when == 0 || when < p.when) {
            // 插入頭部
            msg.next = p;
            mMessages = msg;
        } else {
            // 按時間順序插入中間
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
            }
            msg.next = p;
            prev.next = msg;
        }
        // 喚醒消息隊列(如果之前處于等待狀態(tài))
        notify();
    }
    return true;
}

next()—— 出隊(核心阻塞方法)

Message next() {
    final long ptr = mPtr;
    if (ptr == 0) return null; // 已退出
    long pendingIdleHandlerCount = -1;
    long nextPollTimeoutMillis = 0;
    for (;;) {
        // 阻塞等待,timeout 為 0 表示無限等待
        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) {
                    // 未到執(zhí)行時間,計算等待時間
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 可執(zhí)行,取出消息
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    msg.markInUse();
                    return msg;
                }
            } else {
                // 無消息,無限等待
                nextPollTimeoutMillis = -1;
            }
            // 處理 IdleHandler(空閑時執(zhí)行)
            if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount > 0) {
                // 執(zhí)行空閑任務
            }
        }
    }
}

五、高級特性

1. 同步屏障(Sync Barrier)

用于優(yōu)先處理異步消息(如 UI 繪制),屏蔽同步消息。

應用場景:

  • ViewRootImpl 請求重繪時插入屏障,確保 ChoreographerVSYNC 消息優(yōu)先執(zhí)行
// 插入同步屏障
int token = mHandler.getLooper().getQueue().postSyncBarrier();
// 移除屏障
mHandler.getLooper().getQueue().removeSyncBarrier(token);

?? 濫用可能導致同步消息饑餓,不建議普通應用使用。

2. 空閑處理器(IdleHandler)

MessageQueue 沒有消息需要處理時,會回調 IdleHandler,可用于執(zhí)行低優(yōu)先級任務。

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
    @Override
    public boolean queueIdle() {
        Log.d("IdleHandler", "消息隊列空閑,執(zhí)行預加載");
        // 返回 true:保持注冊;false:執(zhí)行一次后移除
        return false;
    }
});

典型用途:

  • 延遲初始化組件
  • 預加載數據
  • 執(zhí)行非關鍵任務以提升流暢度

3. 異步消息(Asynchronous Message)

避免被同步屏障阻塞,適用于高優(yōu)先級任務。

Message msg = Message.obtain(handler, runnable);
msg.setAsynchronous(true);
handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + 1000);

Handler.createAsync() 可創(chuàng)建專門處理異步消息的 Handler

六、內存優(yōu)化機制

1. Message 對象池(對象復用)

為減少頻繁創(chuàng)建/銷毀對象帶來的 GC 壓力,Message 內部維護了一個對象池。

public final class Message implements Parcelable {
    private static final int MAX_POOL_SIZE = 50;
    private static Message sPool;
    private static int sPoolSize = 0;
    private static final Object sPoolSync = new Object();
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    public void recycle() {
        if (isInUse()) return;
        recycleUnchecked();
    }
    void recycleUnchecked() {
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        target = null;
        callback = null;
        data = null;
        when = 0;
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}

建議始終使用 Message.obtain() 而非 new Message()

七、 使用注意事項

1. 避免內存泄漏

常見場景:非靜態(tài)內部類 Handler 持有外部 Activity 引用,導致無法回收。

解決方案:靜態(tài)內部類 + 弱引用

private static class SafeHandler extends Handler {
    private final WeakReference<MainActivity> mActivity;
    public SafeHandler(MainActivity activity) {
        mActivity = new WeakReference<>(activity);
    }
    @Override
    public void handleMessage(@NonNull Message msg) {
        MainActivity activity = mActivity.get();
        if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
            return;
        }
        switch (msg.what) {
            case 1:
                activity.updateUI((String) msg.obj);
                break;
        }
    }
}

或使用WeakHandler(第三方庫)

// 如 Square 的 LeakCanary 推薦方式
WeakHandler weakHandler = new WeakHandler(this, new Handler.Callback() {
    @Override
    public boolean handleMessage(@NonNull Message msg) {
        // 安全處理
        return true;
    }
});

2. 正確退出 Looper

在子線程中使用 Looper 后,應在適當時機退出,避免資源浪費。

// 安全退出:處理完已到時的消息再退出
handler.getLooper().quitSafely();
// 立即退出:丟棄所有未處理消息
handler.getLooper().quit();

建議在 ThreadonDestroyquit() 方法中調用

3. 主線程 vs 子線程

線程類型Looper 是否自動創(chuàng)建使用方式
主線程(UI線程)是(系統(tǒng)自動調用 Looper.prepareMainLooper()直接創(chuàng)建 Handler
子線程必須手動調用 Looper.prepare()Looper.loop()

八、常見問題與使用建議

問題解決方案
Can't create handler inside thread that has not called Looper.prepare()在子線程中先調用 Looper.prepare()
內存泄漏使用靜態(tài) Handler + WeakReference
消息延遲不準系統(tǒng)休眠或高負載可能導致延遲,不保證精確時間
大量消息堆積控制消息頻率,避免 OOM
使用 postDelayed 實現(xiàn)輪詢不推薦,應使用 AlarmManagerWorkManager 替代

九、總結

Android 的 Handler 機制是一個精巧的線程通信架構,其設計體現(xiàn)了以下幾個關鍵思想:

組件角色設計亮點
Handler消息生產者與消費者提供易用的 API
MessageQueue消息存儲與調度單鏈表 + 時間排序 + 阻塞喚醒機制
Looper消息循環(huán)驅動ThreadLocal + 無限循環(huán)
Message消息載體對象池復用 + 多種數據承載方式

1.核心優(yōu)勢

  • 線程安全:保證 UI 更新在主線程完成
  • 異步解耦:任務可在任意線程發(fā)起,在指定線程執(zhí)行
  • 延遲執(zhí)行:支持定時任務和延遲操作
  • 內存高效:Message 對象池減少 GC 壓力
  • 擴展性強:支持同步屏障、空閑處理器等高級特性

2.應用場景

  • 子線程更新 UI
  • 延遲操作(如啟動頁倒計時)
  • 定時任務(需結合 removeCallbacks 防止泄漏)
  • 線程間狀態(tài)同步

?? 盡管現(xiàn)代 Android 開發(fā)越來越多地使用 Coroutine、LiveData、RxJava 等替代方案,但 Handler 仍是底層基石,理解其原理有助于深入掌握 Android 消息機制。

到此這篇關于Android Handler 機制原理詳解的文章就介紹到這了,更多相關Android Handler 機制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

古蔺县| 华蓥市| 泗水县| 北宁市| 富锦市| 确山县| 岳阳县| 涪陵区| 黄梅县| 措勤县| 高淳县| 昭苏县| 鹿邑县| 双鸭山市| 五家渠市| 竹溪县| 侯马市| 临沭县| 安陆市| 城口县| 邵东县| 广南县| 聊城市| 天水市| 客服| 鹿泉市| 潜山县| 阿拉善左旗| 佛教| 凤凰县| 浏阳市| 光泽县| 甘谷县| 八宿县| 临高县| 游戏| 荣昌县| 绥中县| 肇源县| 家居| 田林县|