Android知识点:Handler

本文详细解析了Android中Handler的工作原理,包括消息传递机制、构造函数使用、实现机制及内存泄露问题。介绍了Handler如何关联线程的Looper和MessageQueue,实现跨线程消息传递,以及如何避免内存泄露。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是Handler

Handler是种消息的传递机制,通过发送Message和处理Meesage和Runnable对象,来关联对应线程的Looper和MessageQueue实现线程消息传递。常用于子线程向主线程发送消息更新ui。当然也有其他用处。

 

二、Handler的使用

1、sendMessage(Message msg)

2、post (Runnable runnable)

上面两个方法最后也是调用了sendMessageAtTime的方法。

 

通过构造函数,获取线程对应Handler的方法:

1、 

Handler mHandler = new Handler();

在主线程线程(只有在主线程中)中使用此方法就可以获取当前线程的handler,默认与当前线程关联。

在子线程从获取主线程关联的hanlder,可以通过

Handler mHandler = new Handler(Looper.getMainLooper());  

或者Handler  mHanlder = Handler.getMain();(其实内部实现跟上面的方式是一致的)

方法生成handler。

2、在子线程中

Looper.prepare();

Handler mHandler = new Hanlder();

Looper.looper();

需要生成一个与线程,相关联的looper,没有传looper,Handler默认获取当前线程的looper

 

总结:获取的是handler跟looper关联的线程有很大关系。

 

三、Handler实现机制

1、Message:Handler传递的消息体,可以通过 Message msg = Message.obtain() 的方式,获取实例,其内部是在重新利用了静态的Message,避免再通过Message的构造函数生成实例,造成内存浪费。

2、MessageQueue :  存放 Message的消息队列,按照先进先出的顺序存放,单链表的数据结构。跟Looper唯一对应,

3、Looper:消息管理器,Looper负责将Message按照先进先出的顺序放进去MessageQuue中,也不断地从MessageQueue中取出Message,执行hanlder的hanlderMessage(Message msg)的方法进行消息传递。一个线程通过prepare()获取一个单例Looper对象,一个线程只能拥有一个Looper实例进行管理,其中是通过ThreadLocal和当前线程做了一一对应关系。

Looper.prepare()

Handler mhandler = new Handler(){

@handlerMessage(Message msg){

}

Looper.loop();

}

 

如上代码,在线程new Handler的时候需要一个与Looper对象对消息进行管理,线程默认不会生成一个Looper对象,而主线程不需要通过Looper.prepare()和Looper.loop(),是因为在app启动的时候,在main函数已经帮我们在主线程用Looper.prepare(),Looper.loop(),的方式生成一个Looper单例与主线程关联,所以不需要关系looper,而在子线程中,默认线程是不会跟looper关联管理message的,所以需要通过Looper.prepare(),生成一个与当前线程关联的looper,而handler与looper关联也是与统一线程,而确认关联关系,或者hanlder传looper对象。

Handler通过sendMessage或者post的方法 发送Message消息,Looper负责将Message按照先进先出的方式将放进去MessageQueue,一个线程维护的Looper单例从MessagQueue中不断需要阻塞的方式取出Message,然后执行Handlder的dispatchMessage()的方法,来执行handlerMessage(),或者回调Runnable的回调方法。

 

四、内存泄露问题

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

1、原因:

      Callback是Hanlder的一个接口,new出来实则是创造了一个匿名类,将以上代码放进acitivty代码当中,则成了一个匿名内部类,而一个匿名内部类持有外部类的实例,可能是activity的实例。当acitivty finish后,而hanlder可能仍然在等待子线程的回调,所以会导致一直持有acitivty的实例。

1、解决办法:

    a、程序逻辑的方式,主动干掉持有acitivty实例的message,可通过 removeCallbacksAndMessages()的方法移除仍然未回调的message;如果因为子线程一直在执行不回调引起的持有acitivty的原因,可将将子线主动结束掉。

   b、static的形式声明为静态内部类,静态内部类不持有外部类的实例,但是不能直接使用外部类的属性方法等,可以通过弱引用的方式。

  c、通过外部类的形式。Callback 在外部实现,handleMessage 再回调 给 activity的方法去执行。

 

另外也有可能是延迟消息,一直存在MessageQueue中,looper就会一直处于阻塞状态,线程也就无法被回收。这时候就需要将MessageQueue中的消息给清除掉,可以调用mHandler.getLooper.quit()或者.quitSafely()(api 18之后);方法清除。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值