浅谈Android中 Handler、Looper、Message不得不说的秘密

作为一名学习Android开发的菜鸟来说,对于Handler、Looper、Message这三者的关系依然是模糊的。因此希望借此文来稍稍谈一下自己对这三者的一些见解。

Handler 主要用于处理Android中线程间通信的问题。有些初学者对Java线程和Android线程不太熟悉,因而也会觉得Handler的理解相对很难。在介绍Handler之前,先带大家了解一下Message和Looper这两个类的一些作用。

先说Message。Message的主要成员变量有四个,分别是what、arg1、arg2和obj。其中what 用于标识消息,arg1和arg2可携带简单的整数类型,obj则是一个封装好的对象。这四个参数可以一起封装在一个Message中,让Message携带这些信息进行线程间的通信。此外,Message类中还有一个比较重要的属性但在实际调用中比较少接触到。那就是target,至于target有什么作用,后面会介绍,现在先放一边。

再到Looper。可能一开始接触对Looper这个类的感觉非常陌生,也很难理解。通过查看Android源码我们发现,事实上Looper这个类的实现,很大部分是通过一个名为ThreadLocal的类来实现的。ThreadLocal又是什么呢?官方定义很多地方都有提到,在这里我想说说我自己的了解。一个Android应用中存在着一个UI主线程,也可以存在着很多个线程。那么对于Android系统来说,它怎么识别出每个线程之间有什么不一样呢?这就要通过ThreadLocal这个类来帮忙了。ThreadLocal里面维护者一个ThreadLoaclMap对象,这个Map中有一个键值对,这个键值对唯一标识着这个线程,而不会让系统混淆同时存在的多个线程。说白了,ThreadLoacl类实际上是用来标识一个线程的,它本身就唯一代表着它所在的线程,而Looper内部唯一实例化了ThreadLocal这个类,也就说明了,一个线程只有唯一对应的ThreadLocal类,也就只有唯一的一个Looper。除此之外,这个Looper类内部还维护着一个MessageQueue,顾名思义也就是消息队列,用来管理消息的进队出队等操作的。因此,Looper这个类实际上既标识着它所在的进程,也起到管理消息队列的作用。

现在来说说Looper里面的几个比较重要的方法。Looper.prepare(), Looper.loop()这两个比较重要。Looper.prepare()方法中,当前线程没有实例化Looper的时候,它会初始化一个Looper,用于管理消息队列;Looper.loop()方法中,存在着一个永真循环,在循环中不断从消息队列中取出一个消息msg,然后交由该msg的目标(target)来处理,接着继续从队列中取出消息,当取出的msg的target为空的时候,跳出循环。可能有人在这时候就会疑惑了,msg的目标到底是什么呢?又是在什么时候设定的呢?

在上面介绍Message的时候说过,Message有个重要的成员属性target。而这个target正是发送这个Message的handler。发送和接收的都是handler,不是很奇怪么?这时候就不得不说一下Handler这个类了。

Handler类是负责处理线程间通信的问题的。说到通信,自然就会有发送接收处理这些功能了。Handler中用sendMessage(Message msg)这个方法负责发送消息,并在这个方法中设定了msg的target就是发送这个消息的handler。然后msg进入到一个MessageQueue中,由关联handler的Looper进行管理,Looper调用loop()方法不断从MessageQueue中取出消息,然后交由msg的target,也就是发送这个msg的handler进行处理。handler调用handleMessage(Message msg)方法对接收到的消息进行处理,可以用于更新UI等等操作,handleMessage这个方法需要我们重写。至此,仍然存在一些疑惑,loop()方法怎么交给handler进行处理消息呢?事实上在loop()方法的源码中,有这样一个关键语句:msg.target.dispatchMessage(msg); 由方法名可以知道,在取出一个消息之后,分发这个消息给对应的target,而在这个dispatchMessage方法中,实际上调用了我们重写的handleMessage()方法,因此即可达到了接收和处理消息的目的。

最后还有一些值得注意的点,handler在哪里实例化,默认关联了它实例化所在的线程的looper。如果想要设定关联其他线程,可以在创建Looper的时候,get到其他线程的标识,然后再关联到handler上,或者在其他线程里进行handler的实例化。

最后献上一个线程内的比较好的写法:


public void run(){
		Looper.prepare();
		handler = new Handler(){
			public void handleMessage(Message msg){
						//Do Something
			}
		}
		Looper.loop();
	}

还有Handler的处理机制图,希望对大家的理解有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值