Android Handler 消息机制之 Looper 深度解析

🔄 一、Looper 的核心作用

Looper 是什么?

复制代码
// Looper 是消息循环的核心,负责:
// 1. 无限循环从 MessageQueue 取消息
// 2. 将消息分发给对应的 Handler
// 3. 管理线程的消息处理能力

为什么需要 Looper?

复制代码
没有 Looper:
┌─────────┐    ┌─────────┐    ┌─────────┐
│ 发送消息 │───▶│ 消息队列 │───▶│ 没人处理 │
└─────────┘    └─────────┘    └─────────┘

有 Looper:
┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
│ 发送消息 │───▶│ 消息队列 │───▶│  Looper  │───▶│ Handler  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘
                        循环读取 ↑   │  分发处理 ↓
                                 └─────┘

⚙️ 二、Looper 源码深度分析

1. Looper 关键字段

复制代码
// Looper.java
public final class Looper {
    // 每个线程独立的 Looper(ThreadLocal)
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
    
    // 消息队列
    private MessageQueue mQueue;
    
    // 当前线程
    private final Thread mThread;
    
    // 主线程的 Looper(特殊处理)
    private static Looper sMainLooper; 
    
    // 是否允许退出
    private boolean mQuitAllowed;
    
    // 是否已经退出
    private boolean mQuitting;
    
    // 用于日志和调试
    private Printer mLogging;
    private Observer mObserver;
    
    // 构造函数(私有,通过 prepare() 创建)
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
        mQuitAllowed = quitAllowed;
    }
}

2. ThreadLocal 机制

复制代码
// ThreadLocal.java - 线程局部变量
public class ThreadLocal<T> {
    // 每个线程有自己的 ThreadLocalMap
    ThreadLocal.ThreadLocalMap threadLocals = null;
    
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }
    
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
}

// 示例:每个线程都有独立的 Looper
Thread 1: ThreadLocal<Looper> → Looper1
Thread 2: ThreadLocal<Looper> → Looper2
Thread 3: ThreadLocal<Looper> → Looper3

🚀 三、Looper 核心方法详解

1. prepare() - 初始化 Looper

复制代码
// 准备当前线程的 Looper
public static void prepare() {
    prepare(true);  // 默认允许退出
}

private static void prepare(boolean quitAllowed) {
    // 检查是否已经 prepare 过
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    
    // 创建 Looper 并设置到 ThreadLocal
    sThreadLocal.set(new Looper(quitAllowed));
    
    Log.d(TAG, "Looper prepared for thread: " + Thread.currentThread().getName());
}

// 主线程的特殊 prepare
public static void prepareMainLooper() {
    prepare(false);  // 主线程不允许退出
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

2. loop() - 消息循环的核心

复制代码
// 核心方法:开始消息循环
public static void loop() {
    // 1. 获取当前线程的 Looper
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    
    // 2. 获取消息队列
    final MessageQueue queue = me.mQueue;
    
    // 3. 清除线程的调用者标识
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    
    // 4. 开始无限循环
    for (;;) {
        // 5. 从队列取消息(可能阻塞)
        Message msg = queue.next(); 
        if (msg == null) {
            // 没有消息表示队列正在退出
            return;
        }
        
        // 6. 打印日志(如果有设置)
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }
        
        // 7. 观察者通知(用于性能监控)
        final Observer observer = sObserver;
        final long traceTag = me.mTraceTag;
        if (observer != null) {
            observer.messageDispatchStarting();
        }
        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }
        
        try {
            // 8. 关键:分发消息给 Handler
            msg.target.dispatchMessage(msg);
        } catch (Exception exception) {
            // 9. 异常处理
            Log.w(TAG, "Exception thrown in message dispatch", exception);
        } finally {
            // 10. 结束跟踪
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        
        // 11. 打印结束日志
        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }
        
        // 12. 观察者通知结束
        if (observer != null) {
            observer.messageDispatched();
        }
        
        // 13. 恢复调用者标识
        Binder.restoreCallingIdentity(ident);
        
        // 14. 回收消息对象
        msg.recycleUnchecked();
    }
}

3. myLooper() - 获取当前线程的 Looper

复制代码
// 获取当前线程的 Looper
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

// 获取主线程 Looper
public static Looper getMainLooper() {
    synchronized (Looper.class) {
        return sMainLooper;
    }
}

// 判断当前线程是否是主线程
public static boolean isMainThread() {
    return Looper.getMainLooper().getThread() == Thread.currentThread();
}

4. quit() / quitSafely() - 退出循环

复制代码
// 立即退出(不推荐)
public void quit() {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }
    
    synchronized (this) {
        if (mQuitting) {
            return;
        }
        mQuitting = true;
        mQueue.quit(false);  // 立即退出
    }
}

// 安全退出(等待消息处理完)
public void quitSafely() {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }
    
    synchronized (this) {
        if (mQuitting) {
            return;
        }
        mQuitting = true;
        mQueue.quit(true);  // 安全退出
    }
}

📊 四、Looper 工作原理流程图

Looper 工作流程详解

复制代码
/*
启动流程:
1. Looper.prepare()      ← 创建 Looper
2. Handler 创建           ← 关联 Looper
3. Looper.loop()         ← 开始循环
4. Handler 发送消息        ← 外部调用
5. MessageQueue.enqueueMessage()
6. Looper.loop() 中的 queue.next()
7. Handler.dispatchMessage()
8. 处理消息/回到步骤6
*/

消息循环状态图

复制代码
┌─────────────────────────────────────┐
│            Looper.loop()             │
├─────────────────────────────────────┤
│   for (;;) {                        │
│     1. Message msg = queue.next();  │
│        ├─ 队列为空 → 阻塞等待         │
│        ├─ 有同步屏障 → 找异步消息      │
│        └─ 有消息到达 → 取出消息        │
│                                    │
│     2. msg.target.dispatchMessage() │
│        ├─ msg.callback != null      │
│        │   → handleCallback()       │
│        ├─ mCallback != null         │
│        │   → mCallback.handleMessage()│
│        └─ handleMessage()           │
│                                    │
│     3. msg.recycleUnchecked()       │
│   }                                 │
└─────────────────────────────────────┘

🎯 五、Looper 在 Android 系统中的使用

1. 主线程 Looper(UI 线程)

复制代码
// ActivityThread.java - Android 应用主入口
public static void main(String[] args) {
    // 1. 准备主线程 Looper
    Looper.prepareMainLooper();
    
    // 2. 创建 ActivityThread
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    
    // 3. 设置主线程 Handler
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    
    // 4. 开始消息循环(永不退出)
    Looper.loop();
    
    // 理论上不会执行到这里
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

// 获取主线程 Handler
public static Handler getMainThreadHandler() {
    return sMainThreadHandler;
}

2. HandlerThread(自带 Looper 的工作线程)

复制代码
// HandlerThread.java - Android 封装类
public class HandlerThread extends Thread {
    
    private Looper mLooper;
    
    @Override
    public void run() {
        // 1. 设置线程优先级
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        
        // 2. 准备 Looper
        Looper.prepare();
        
        synchronized (this) {
            // 3. 获取 Looper
            mLooper = Looper.myLooper();
            notifyAll();  // 通知等待的线程
        }
        
        // 4. 开始循环
        Looper.loop();
    }
    
    // 获取 Looper(会等待 Looper 创建完成)
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();  // 等待 Looper 创建
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    
    // 退出
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
}

3. 子线程创建 Looper 的完整示例

复制代码
// WorkerThreadWithLooper.java
public class WorkerThreadWithLooper extends Thread {
    
    private Looper mLooper;
    private Handler mHandler;
    private CountDownLatch mLatch = new CountDownLatch(1);
    
    @Override
    public void run() {
        Log.d("WorkerThread", "线程启动: " + Thread.currentThread().getId());
        
        // 1. 准备 Looper
        Looper.prepare();
        
        // 2. 获取 Looper 并通知等待的线程
        synchronized (this) {
            mLooper = Looper.myLooper();
            mLatch.countDown();  // 通知 Looper 已准备好
        }
        
        // 3. 创建 Handler
        mHandler = new Handler(mLooper) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1:
                        processTask((String) msg.obj);
                        break;
                    case 2:
                        stopLooper();
                        break;
                }
            }
        };
        
        // 4. 开始消息循环(阻塞在这里)
        Log.d("WorkerThread", "开始消息循环");
        Looper.loop();
        
        // 5. loop() 退出后执行
        Log.d("WorkerThread", "消息循环结束,线程退出");
    }
    
    // 等待 Looper 创建完成
    public void waitForLooper() throws InterruptedException {
        mLatch.await();
    }
    
    // 获取 Handler(用于外部发送消息)
    public Handler getHandler() {
        return mHandler;
    }
    
    // 获取 Looper
    public Looper getLooper() {
        return mLooper;
    }
    
    // 处理任务
    private void processTask(String task) {
        Log.d("WorkerThread", "处理任务: " + task);
        
        // 模拟耗时操作
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        Log.d("WorkerThread", "任务完成: " + task);
    }
    
    // 停止 Looper
    private void stopLooper() {
        if (mLooper != null) {
            mLooper.quitSafely();
        }
    }
    
    // 发送任务
    public void sendTask(String task) {
        if (mHandler != null) {
            Message msg = mHandler.obtainMessage(1, task);
            mHandler.sendMessage(msg);
        }
    }
    
    // 延迟发送任务
    public void sendDelayedTask(String task, long delay) {
        if (mHandler != null) {
            Message msg = mHandler.obtainMessage(1, task);
            mHandler.sendMessageDelayed(msg, delay);
        }
    }
    
    // 停止线程
    public void stopThread() {
        if (mHandler != null) {
            mHandler.sendEmptyMessage(2);
        }
    }
}

// 使用示例
public class LooperExampleActivity extends AppCompatActivity {
    
    private WorkerThreadWithLooper workerThread;
    private TextView textView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        
        // 创建并启动工作线程
        workerThread = new WorkerThreadWithLooper();
        workerThread.start();
        
        // 等待 Looper 初始化完成
        new Thread(() -> {
            try {
                workerThread.waitForLooper();
                
                // Looper 已准备好,可以发送消息
                runOnUiThread(() -> {
                    textView.setText("工作线程 Looper 已准备就绪");
                });
                
                // 发送任务到工作线程
                workerThread.sendTask("第一个任务");
                workerThread.sendDelayedTask("延迟任务", 2000);
                
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 停止工作线程
        if (workerThread != null) {
            workerThread.stopThread();
        }
    }
}

⚡ 六、Looper 的高级特性

1. 同步屏障(Sync Barrier)

复制代码
// 同步屏障:确保异步消息优先执行
public class SyncBarrierExample {
    
    public void demonstrateSyncBarrier() {
        Handler handler = new Handler(Looper.getMainLooper());
        MessageQueue queue = Looper.getMainLooper().getQueue();
        
        // 1. 发送普通消息
        handler.post(() -> Log.d("SyncBarrier", "普通消息 1"));
        handler.post(() -> Log.d("SyncBarrier", "普通消息 2"));
        
        // 2. 插入同步屏障(反射调用)
        try {
            Method postSyncBarrier = MessageQueue.class.getDeclaredMethod(
                "postSyncBarrier");
            postSyncBarrier.setAccessible(true);
            int token = (int) postSyncBarrier.invoke(queue);
            
            // 3. 发送异步消息(会优先执行)
            Message asyncMsg = Message.obtain(handler, () -> {
                Log.d("SyncBarrier", "异步消息(优先执行)");
            });
            asyncMsg.setAsynchronous(true);
            handler.sendMessage(asyncMsg);
            
            // 4. 发送更多普通消息(会被阻塞)
            handler.post(() -> Log.d("SyncBarrier", "普通消息 3(被阻塞)"));
            
            // 5. 移除屏障
            Method removeSyncBarrier = MessageQueue.class.getDeclaredMethod(
                "removeSyncBarrier", int.class);
            removeSyncBarrier.setAccessible(true);
            removeSyncBarrier.invoke(queue, token);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    // 输出顺序:
    // 1. 异步消息(优先执行)
    // 2. 普通消息 1
    // 3. 普通消息 2
    // 4. 普通消息 3(被阻塞)
}

2. IdleHandler(空闲处理器)

复制代码
// IdleHandler:在消息队列空闲时执行
public class IdleHandlerExample {
    
    private int idleCount = 0;
    
    public void useIdleHandler() {
        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                // 在消息队列空闲时调用
                Log.d("IdleHandler", "队列空闲,执行空闲任务 " + (++idleCount));
                
                // 返回 true 表示保持注册,下次空闲还会调用
                // 返回 false 表示只执行一次
                return idleCount < 3;  // 最多执行3次
            }
        });
    }
    
    // 实际应用:延迟加载
    public void lazyLoadWithIdleHandler() {
        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                // 在界面渲染完成后,空闲时加载非关键数据
                loadSecondaryData();
                loadRecommendations();
                return false;  // 只执行一次
            }
        });
    }
}

3. Looper 与 ANR 的关系

复制代码
// ANR(Application Not Responding)产生原因
public class ANRAnalysis {
    
    // ANR 监控机制
    private void monitorANR() {
        // Android 系统监控:
        // 1. Input 事件 5秒内未处理 → ANR
        // 2. BroadcastReceiver 10秒内未完成 → ANR
        // 3. Service 20秒内未完成 → ANR
        
        // 根本原因:Looper 的消息处理被阻塞
        Handler mainHandler = new Handler(Looper.getMainLooper());
        
        // ❌ 错误:阻塞主线程 Looper
        mainHandler.post(() -> {
            try {
                Thread.sleep(10000);  // 阻塞10秒 → ANR
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        // ✅ 正确:耗时操作在子线程
        new Thread(() -> {
            // 耗时操作
            String result = doHeavyWork();
            
            // 完成后通知主线程
            mainHandler.post(() -> updateUI(result));
        }).start();
    }
}

4. Looper 性能监控

复制代码
// 使用 Printer 监控 Looper 性能
public class LooperMonitor {
    
    public void startMonitoring() {
        Looper.getMainLooper().setMessageLogging(new Printer() {
            private static final String START = ">>>>> Dispatching";
            private static final String END = "<<<<< Finished";
            private long startTime = 0;
            
            @Override
            public void println(String x) {
                if (x.startsWith(START)) {
                    // 开始处理消息
                    startTime = System.currentTimeMillis();
                    Log.d("LooperMonitor", "开始处理消息: " + x);
                    
                } else if (x.startsWith(END)) {
                    // 结束处理消息
                    long duration = System.currentTimeMillis() - startTime;
                    Log.d("LooperMonitor", "消息处理完成,耗时: " + duration + "ms");
                    
                    // 检测是否可能 ANR
                    if (duration > 100) {  // 超过100ms警告
                        Log.w("LooperMonitor", "消息处理时间过长: " + duration + "ms");
                        printStackTrace();
                    }
                }
            }
            
            private void printStackTrace() {
                // 打印调用栈,找到耗时操作
                StackTraceElement[] stackTrace = Looper.getMainLooper()
                    .getThread().getStackTrace();
                for (StackTraceElement element : stackTrace) {
                    Log.w("LooperMonitor", element.toString());
                }
            }
        });
    }
}

🔧 七、Looper 常见问题与解决方案

问题1:Looper 未 prepare

复制代码
// ❌ 错误:在子线程直接创建 Handler
new Thread(() -> {
    Handler handler = new Handler();  // 崩溃:No Looper
    handler.post(() -> {});
}).start();

// ✅ 解决方案1:先 prepare
new Thread(() -> {
    Looper.prepare();
    Handler handler = new Handler();
    Looper.loop();  // 开始循环
}).start();

// ✅ 解决方案2:使用主线程 Looper
new Thread(() -> {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(() -> {
        // 在主线程执行
    });
}).start();

问题2:Looper 无法退出

复制代码
// 场景:子线程 Looper 需要正确退出
public class LooperExitExample {
    
    private Thread workerThread;
    private Handler workerHandler;
    
    public void startWorker() {
        workerThread = new Thread(() -> {
            Looper.prepare();
            
            workerHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == MSG_EXIT) {
                        // 退出 Looper
                        Looper.myLooper().quitSafely();
                    }
                }
            };
            
            Looper.loop();  // 阻塞在这里
            
            // Looper 退出后执行
            Log.d("LooperExit", "Looper 已退出");
        });
        
        workerThread.start();
    }
    
    public void stopWorker() {
        if (workerHandler != null) {
            // 发送退出消息
            workerHandler.sendEmptyMessage(MSG_EXIT);
        }
    }
    
    // ❌ 错误:直接调用 quit(),可能丢失未处理的消息
    public void stopWorkerWrong() {
        if (workerHandler != null) {
            workerHandler.getLooper().quit();  // 立即退出,可能丢消息
        }
    }
}

问题3:内存泄漏

复制代码
// 场景:Handler 持有 Activity 引用,Looper 持有 Handler
public class LeakActivity extends Activity {
    
    // ❌ 错误:匿名 Handler 持有 Activity 引用
    private Handler leakHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            // 隐式持有外部 Activity 引用
            updateUI();
        }
    };
    
    // ✅ 解决方案:静态内部类 + 弱引用
    private static class SafeHandler extends Handler {
        private final WeakReference<LeakActivity> activityRef;
        
        SafeHandler(LeakActivity activity) {
            super(Looper.getMainLooper());
            activityRef = new WeakReference<>(activity);
        }
        
        @Override
        public void handleMessage(Message msg) {
            LeakActivity activity = activityRef.get();
            if (activity != null && !activity.isFinishing()) {
                activity.handleMessage(msg);
            }
        }
    }
    
    private SafeHandler safeHandler;
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 移除所有消息
        if (safeHandler != null) {
            safeHandler.removeCallbacksAndMessages(null);
        }
    }
}

问题4:Looper 死锁

复制代码
// 场景:消息处理中又同步等待其他消息
public class DeadlockExample {
    
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    private Object lock = new Object();
    private boolean taskDone = false;
    
    // ❌ 错误:在主线程同步等待
    public void performTaskWithDeadlock() {
        mainHandler.post(() -> {
            // 发送任务到子线程
            new Thread(() -> {
                // 模拟耗时任务
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                // 通知主线程任务完成
                synchronized (lock) {
                    taskDone = true;
                    lock.notifyAll();
                }
            }).start();
            
            // 在主线程同步等待(导致死锁)
            synchronized (lock) {
                while (!taskDone) {
                    try {
                        lock.wait();  // 阻塞主线程 Looper
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            
            Log.d("Deadlock", "任务完成");
        });
    }
    
    // ✅ 正确:使用回调而不是同步等待
    public void performTaskCorrectly() {
        mainHandler.post(() -> {
            // 发送任务到子线程
            new Thread(() -> {
                // 模拟耗时任务
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                // 完成后回调到主线程
                mainHandler.post(() -> {
                    Log.d("Correct", "任务完成,更新UI");
                });
            }).start();
        });
    }
}

📊 八、Looper 性能优化

1. 减少主线程 Looper 负担

复制代码
public class LooperOptimization {
    
    // ❌ 错误:频繁发送小消息
    private void sendManySmallMessages() {
        Handler handler = new Handler(Looper.getMainLooper());
        for (int i = 0; i < 100; i++) {
            handler.post(() -> {
                // 更新UI的很小一部分
                textView.setText("更新 " + i);
            });
        }
    }
    
    // ✅ 正确:合并消息
    private void sendBatchMessage() {
        Handler handler = new Handler(Looper.getMainLooper());
        
        // 合并数据
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 100; i++) {
            builder.append("数据").append(i).append(" ");
        }
        
        // 一次发送
        handler.post(() -> {
            textView.setText(builder.toString());
        });
    }
    
    // ✅ 使用 View.post() 替代 Handler
    private void useViewPost() {
        // View.post() 内部使用 Handler,但更简洁
        textView.post(() -> {
            textView.setText("直接更新");
        });
    }
}

2. 合理使用 IdleHandler

复制代码
public class IdleHandlerOptimization {
    
    public void optimizeWithIdleHandler() {
        // 在界面加载时,先加载关键数据
        loadCriticalData();
        
        // 使用 IdleHandler 加载非关键数据
        Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                // 在 UI 渲染完成后加载
                loadNonCriticalData();
                loadCacheData();
                return false;  // 只执行一次
            }
        });
    }
}

3. 避免消息队列过大

复制代码
public class MessageQueueOptimization {
    
    private Handler handler;
    private static final int MAX_PENDING_MESSAGES = 50;
    
    public void sendMessageWithLimit(Message msg) {
        // 检查队列大小
        if (getPendingMessageCount() > MAX_PENDING_MESSAGES) {
            // 队列过大,丢弃旧消息或合并消息
            handler.removeMessages(msg.what);
            Log.w("Optimization", "消息队列过大,移除旧消息");
        }
        
        handler.sendMessage(msg);
    }
    
    private int getPendingMessageCount() {
        // 通过反射获取消息队列大小(仅用于调试)
        try {
            Field field = MessageQueue.class.getDeclaredField("mMessages");
            field.setAccessible(true);
            Message msg = (Message) field.get(handler.getLooper().getQueue());
            
            int count = 0;
            while (msg != null) {
                count++;
                msg = msg.next;
            }
            return count;
        } catch (Exception e) {
            return -1;
        }
    }
}

🎯 九、Looper 的最佳实践

1. 主线程 Looper 使用规范

复制代码
public class MainThreadLooperRules {
    
    // 规则1:使用 Looper.getMainLooper() 获取主线程 Looper
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    
    // 规则2:不在主线程执行耗时操作
    public void updateUIWithData() {
        // 耗时操作在子线程
        new Thread(() -> {
            String data = fetchDataFromNetwork();
            
            // 使用 Handler 更新 UI
            mainHandler.post(() -> {
                textView.setText(data);
            });
        }).start();
    }
    
    // 规则3:及时移除消息
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mainHandler.removeCallbacksAndMessages(null);
    }
}

2. 工作线程 Looper 使用规范

复制代码
public class WorkerThreadLooperRules {
    
    private HandlerThread handlerThread;
    private Handler workerHandler;
    
    public void setupWorkerThread() {
        // 使用 HandlerThread(Android 封装好的)
        handlerThread = new HandlerThread("WorkerThread");
        handlerThread.start();
        
        // 获取 Handler
        workerHandler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                // 在工作线程处理消息
                processTask(msg);
            }
        };
    }
    
    public void cleanup() {
        // 正确退出
        if (handlerThread != null) {
            handlerThread.quitSafely();
            try {
                handlerThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3. Looper 调试技巧

复制代码
public class LooperDebugging {
    
    // 方法1:设置 Logging 监控
    public void setupLooperLogging() {
        Looper.getMainLooper().setMessageLogging(new Printer() {
            @Override
            public void println(String x) {
                if (x.startsWith(">>>>> Dispatching")) {
                    Log.d("LooperDebug", "开始处理: " + x);
                } else if (x.startsWith("<<<<< Finished")) {
                    Log.d("LooperDebug", "处理完成: " + x);
                }
            }
        });
    }
    
    // 方法2:检测主线程卡顿
    public void detectMainThreadStuck() {
        Handler handler = new Handler(Looper.getMainLooper());
        
        // 监控消息处理时间
        handler.postDelayed(() -> {
            // 这个 Runnable 应该很快被执行
            Log.d("LooperDebug", "监控任务执行");
        }, 100);
        
        // 如果超过 500ms 未执行,说明主线程卡顿
        handler.postDelayed(() -> {
            Log.w("LooperDebug", "主线程可能卡顿");
        }, 600);
    }
    
    // 方法3:打印消息队列状态
    public void printMessageQueueStatus() {
        MessageQueue queue = Looper.getMainLooper().getQueue();
        
        try {
            Field field = MessageQueue.class.getDeclaredField("mMessages");
            field.setAccessible(true);
            Message msg = (Message) field.get(queue);
            
            int count = 0;
            while (msg != null) {
                count++;
                Log.d("QueueStatus", "消息 " + count + ": what=" + msg.what);
                msg = msg.next;
            }
            
            Log.d("QueueStatus", "总消息数: " + count);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

🔮 十、Looper 在现代 Android 中的演进

1. Kotlin 协程替代方案

复制代码
// 使用协程代替 Handler/Looper
class CoroutineExample : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 启动协程
        lifecycleScope.launch {
            // 自动切换线程
            val data = withContext(Dispatchers.IO) {
                fetchData()  // 在 IO 线程执行
            }
            
            updateUI(data)  // 在主线程执行(自动切换)
        }
    }
}

2. LiveData 自动线程切换

复制代码
// LiveData 内部使用 Handler 进行线程切换
public class LiveDataExample extends ViewModel {
    
    private MutableLiveData<String> data = new MutableLiveData<>();
    
    public void loadData() {
        // 在后台线程
        Executors.newSingleThreadExecutor().execute(() -> {
            String result = fetchData();
            
            // 自动切换到主线程
            data.postValue(result);
        });
    }
}

3. Executor 框架

复制代码
// 使用 Executor 管理线程
public class ExecutorExample {
    
    private Executor mainExecutor = new Executor() {
        private Handler handler = new Handler(Looper.getMainLooper());
        
        @Override
        public void execute(Runnable command) {
            handler.post(command);
        }
    };
    
    private ExecutorService backgroundExecutor = 
        Executors.newFixedThreadPool(4);
    
    public void executeTask(Runnable backgroundTask, Runnable uiTask) {
        backgroundExecutor.execute(() -> {
            backgroundTask.run();
            mainExecutor.execute(uiTask);
        });
    }
}

✅ 总结:Looper 的核心要点

关键知识点:

    1. 每个线程最多一个 Looper(通过 ThreadLocal 保证)
    1. Looper 必须调用 prepare() 才能使用
    1. loop() 是死循环,会阻塞当前线程
    1. 主线程 Looper 不能退出
    1. 消息处理顺序:同步屏障 → 异步消息 → 普通消息

使用场景建议:

  • UI 更新 :使用主线程 Handler(Looper.getMainLooper()
  • 后台任务 :使用 HandlerThread 或自定义线程 + Looper
  • 定时任务 :使用 Handler.postDelayed()
  • 空闲任务 :使用 IdleHandler
  • 紧急任务:使用异步消息 + 同步屏障

性能建议:

    1. ✅ 避免在主线程执行耗时操作
    1. ✅ 合理使用消息合并和批量发送
    1. ✅ 及时移除不再需要的消息
    1. ✅ 使用消息池(Message.obtain()
    1. ✅ 监控 Looper 性能,避免 ANR
相关推荐
Mr YiRan2 小时前
Android 16KB 腾讯Mars XLog适配
android
2501_915921432 小时前
不用 Xcode 上架 iOS,拆分流程多工具协作完成 iOS 应用的发布准备与提交流程
android·macos·ios·小程序·uni-app·iphone·xcode
子木鑫2 小时前
[SUCTF2019 & GXYCTF2019] 文件上传绕过实战:图片马 + .user.ini / .htaccess 构造 PHP 后门
android·开发语言·安全·php
一起养小猫2 小时前
Flutter for OpenHarmony 实战:打造功能完整的记账助手应用
android·前端·flutter·游戏·harmonyos
_乐无3 小时前
Unity 发布 Android 安卓端所有文件可读写
android·unity·游戏引擎
User_芊芊君子3 小时前
【LeetCode原地复写零】:双指针+逆向填充,O(n)时间O(1)空间最优解!
android·linux·leetcode
2501_944448005 小时前
Flutter for OpenHarmony衣橱管家App实战:支持我们功能实现
android·javascript·flutter
2601_9498333914 小时前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter
2603_9494621016 小时前
Flutter for OpenHarmony社团管理App实战:预算管理实现
android·javascript·flutter