Android消息机制详解

本文详细探讨了Android消息机制,包括其用于线程间通信的目的、不能在主线程外更新UI的原因、线程间通信的方式以及Message、MessageQueue、Looper和Handler的核心要素。并介绍了防止内存泄漏的处理策略以及消息的发送和读取流程。
摘要由CSDN通过智能技术生成

use for

相信于此,绝大多数同学都会回答消息机制是android 为了线程间通信而引入的工具。可以轻松的将一个任务切换到handler所在线程执行。android开发规范有规定,不允许于子线程更新ui,这样会触发异常;我们平时使用handler主要都是将子线程切换到主线程中去执行;因此从本质上来来说,Handler并不是专门用于更新UI的,它只是常被开发者用来更新UI。

Q?为何不能在主线程外更新ui呢?

A:因为Android的UI线程是非线程安全的,应用更新UI,是调用invalidate()方法来实现界面的重绘,而invalidate()方法是非线程安全的,也就是说当我们在非UI线程来更新UI时,可能会有其他的线程或UI线程也在更新UI,这就会导致界面更新的不同步。因此我们不能在非UI主线程中做更新UI的操作。也就是说我们在使用Android中的线程时,要保证: 更新ui都在UI主线程执行.

Q: 那为何不将需要更新ui的操作放在UI线程执行呢?

**A:**我们都知道在java中,线程存在以下几种基本状态:创建,就绪运行阻塞,死亡。我们的应用启动后,所有的交互都是在UI线程完成的;如果在UI执行延时操作,如常见的网络请求UI线程就会进入阻塞状态;此时用户就无法响应任何操作了;如果此过程超过5秒,就会让程序处于ANR(application not response),这时用户就可能想要和你的应用说声gg了。

Q :Android提供了哪几种线程间通信方式?

A:AsyncTask?,Handler 。为什么AsynTask打了个?呢,我们可以简单看下AsynTask源码,他内部也是接住handler来进行线程间通信的。

Q:messageQueue****可以取没有Targer对象的消息,那和我们正常流程中,消息来源是不是有出入?

A 其实平时我们使用的Message,都是通过Handler发送的,有一些系统消息,他们会直接通过调用MessageQueue发送一个屏障消息,这类消息没有Target,然后配合Handler发送异步消息来使用;当MessageQueue读取到屏障消息后,他们会直接在链表中找到最近的异步消息,直接执行。

feature-要素

· Message(消息单元)

定义一个可以发送到Handler的消息;它定义了消息Id,两个额为的int字段和一个额外的object字段(消息处理对象),它们可以不被初始化;虽然它的构造方法是public,但是还是建议我们通过obtain系列函数进行定义。

· MessageQueue(消息队列)

存放所有发送的消息队列,单链表结构,供Looper从中读取数据;延时消息是怎么存取的,这个很有趣;

· Looper(消息读取者)

永动机;其中有个死循环函数Loop(),不断读取MessageQueue中的消息,交给目标处理;问题来了,既然是个死循环,那不是始终会阻塞Looper所在线程吗。这又是如何解决的。

· Handler(消息分发以及处理者)

通过sendMessage系列函数,会将Message传入MessageQueue中;Looper.loop()读取到消息传递给Handler处理。

desc

  1. handler创建前,Looper.loop()执行前;需要保证当前线程Looper有创建,而这个保证即Looper.prepare();主线程由于在ActivityThread创建时,已经做过,所以无需执行;

  2. Looper.loop()中有一个死循环,所以线程资源不会释放;MessageQueue中的quit函数,我们才能释放资源;

  3. Java中,所有非静态成员变量会持有当前对象的引用(不然你又是怎么引用外部类的各种成员变量和函数等);那样我们在Activity中通过new Handler() , 创建的对象会持有当前页面的引用;而我们发送的每个消息不能保证是立即执行,以及迅速执行结束的,handler.sendEmptyMessageDelayed;消息是会持有handler做为他的target,那在这个message在通过msg.target.dispatchMessage(msg);会一直被持有;这样会导致messageQueue->message->handler->activity|fragment;在页面被销毁,声明周期执行到desatory时,activity不会得到释放,从而内存泄漏handler得到消息处理时,如果当前页面已经被销毁,执行Ui更新,又会导致难以预料的问题。

  4. 针对3所提的我们可以按以下两种处理:1:页面destory销毁时,调用handler.removeCallbacksAndMessages(null);2:通过软引用创建静态Handler对象;

流程解析

android handler流程分析晚上有很多资料;我们这儿简单介绍下:

· Looper,MessageQueue 就绪;调用Looper.prepare(),其间会向Looper静态线程变量sThreadLocal插入一个当前线程的Looper;在调用Looper构造函数时,我们会初始化MessageQueue,并将mThread设置为当前Thread.currentThread();

· Looper.prepare()代码块如下:

public static void prepare() {
        prepare(true);
 } ​ 
private static void prepare(boolean quitAllowed) {
    //sThreadLocal->ThreadLocal对象,里面封装了一个map逻辑,key是线程hash值;static 类变量 
    if (sThreadLocal.get() != null) {//不允许多次 prepare
        throw new RuntimeException("Only one Looper may be created per thread");
       }
       sThreadLocal.set(new Looper(quitAllowed));//设置当前线程的Looper
 }

Looper构造函数,以及MessageQueue构造函数如下:

 private Looper(boolean
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值