Android Handler

本文详细解释了在Android开发中如何避免由Handler引起的内存泄漏。主要讨论了非静态内部类和匿名类持有对外部类引用的问题,以及如何通过将Handler声明为静态嵌套类并使用弱引用解决这一问题。

static or leaks

This Handler class should be static or leaks might occur (anonymous android.os.Handler).
Handler 类应该应该为static类型,否则有可能造成泄露。在程序消息队列中排队的消息保持了对目标Handler类的应用。如果Handler是个内部类,那 么它也会保持它所在的外部类的引用。为了避免泄露这个外部类,应该将Handler声明为static嵌套类,并且使用对外部类的弱应用。

在Java 中:非静态的内部类和匿名类都会隐式的持有一份对外部类的引用,而静态的内部类则不会包含对外部类的引用。

有如下两种解决方法:

(1)官方建议

private Handler mHandler = new Handler(new Handler.Callback() {  
         
       @Override  
       public boolean handleMessage(Message msg) {  
           return false;  
       }  
   }); 

(2)静态类

static class MyHandler extends Handler {  
    WeakReference<OuterClass> outerClass;  
 
    MyHandler(OuterClass activity) {  
        outerClass = new WeakReference<OuterClass>(activity);  
    }  
 
    @Override  
    public void handleMessage(android.os.Message msg) {  
        OuterClass theClass = outerClass.get();  
        switch (msg.what) {  
        case 0: {  
            //使用theClass访问外部类成员和方法  
            break;  
        }  
        default: {  
            Log.w(TAG, "未知的Handler Message:" + msg.what);  
        }  
        }  
 
    }  
}  

### Android Handler 使用与常见问题 在 Android 开发中,`Handler` 是用于在不同线程之间通信的重要工具。它主要用于将任务(如 UI 更新)从后台线程传递到主线程执行,从而避免主线程阻塞并确保 UI 的流畅性。 #### Handler 的基本使用 `Handler` 通常与 `Looper` 和 `MessageQueue` 配合使用。每个 `Handler` 实例都与一个线程及其消息队列相关联。通过 `Handler`,可以发送和处理消息(`Message`)或运行 `Runnable` 对象。 以下是一个简单的 `Handler` 示例: ```java Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { // 更新 UI 的代码 } }); ``` 在子线程中使用 `Handler` 时,需要确保该线程已经调用了 `Looper.prepare()` 并启动了 `Looper.loop()`,否则会抛出异常。 #### 常见问题 1. **内存泄漏** 如果 `Handler` 持有对 `Activity` 或 `Context` 的引用,并且在子线程中长时间运行,可能会导致内存泄漏。为避免这种情况,通常建议使用静态内部类或弱引用(`WeakReference`)来持有外部类的引用。 ```java private static class MyHandler extends Handler { private final WeakReference<Activity> mActivityReference; public MyHandler(Activity activity) { mActivityReference = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { Activity activity = mActivityReference.get(); if (activity != null) { // 处理消息 } } } ``` 2. **消息延迟与顺序问题** 使用 `sendMessageDelayed()` 或 `postDelayed()` 可以实现延迟执行任务的功能。然而,如果多次发送相同的消息或 `Runnable`,可能会导致消息堆积,影响程序的响应速度。为避免此类问题,可以使用 `removeCallbacks()` 或 `removeMessages()` 来清理不再需要的消息。 3. **线程安全问题** 虽然 `Handler` 本身是线程安全的,但如果多个线程同时操作共享的数据结构,仍然需要额外的同步机制。例如,使用 `synchronized` 关键字或 `ReentrantLock` 来确保数据的一致性。 4. **主线程阻塞** 如果在 `Handler` 中执行耗时操作,可能会阻塞主线程,导致 ANR(Application Not Responding)错误。应避免在 `Handler` 中执行网络请求、数据库查询等耗时任务,建议使用 `AsyncTask`、`Thread` 或 `ExecutorService` 来处理这些操作。 5. **Looper 未初始化** 在非主线程中使用 `Handler` 时,必须手动调用 `Looper.prepare()` 来创建 `MessageQueue`,并在最后调用 `Looper.loop()` 来开始处理消息。如果忘记调用这些方法,会导致运行时异常。 ```java new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }).start(); ``` 6. **消息优先级** 默认情况下,所有消息的优先级相同。如果需要处理高优先级的任务,可以通过 `Message` 的 `setAsynchronous()` 方法来标记异步消息,但这需要底层支持(如 `ViewRootImpl` 的 `Choreographer`)。 #### 总结 `Handler` 是 Android 中实现线程间通信的核心机制之一,但其使用过程中需要注意内存管理、线程安全、消息顺序等问题。合理使用 `Handler` 可以提升应用的响应能力和用户体验。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值