Handle初解,看完你就懂了handle
文章目录
- 前言
- 一、Handle是什么?
- 二、Handle有啥用呢?
- 1.传递消息到ui线程
- 2.代码示例
- 3注意点
- 最后
前言
提示:看完本篇,你可以了解到Handle的相关知识与常见的误区提醒
一、Handle是什么?
我们查看一下谷歌官方对其的定义:
A Handler allows you to send and process {@link Message} and Runnable
objects associated with a thread’s {@link MessageQueue}. Each Handler
instance is associated with a single thread and that thread’s message
queue. When you create a new Handler, it is bound to the thread /
message queue of the thread that is creating it – from that point on,
it will deliver messages and runnables to that message queue and execute
them as they come out of the message queue.
Handler它可以通过消息队列发送消息或者runable对象,也可以处理消息或者runable对象。每一个handler实例,都持有一个线程以及此线程的消息队列。
那么handle相当于什么呢?其实就相当于我们现实世界的搬运工,可以发送消息,也可以处理消息。
二、Handle有啥用呢?
1.传递消息到ui线程
在我们安卓开发的时候,我们都知道ui线程是不可以进行耗时操作的,如果在这里进行的话,就会导致ANR,因此开辟一个子线程,在子线程中去处理相关的耗时任务,这是必然的结果。那么处理完的结果需要改变ui,即我们的控件显示的时候怎么办呢?在子线程中处理完直接改变ui是安卓中不允许的行为,因为ui线程不是线程安全的,那么我们有必要需要一个工具将子线程处理的结果带回去给ui线程去显示,而handle正是完成了这个任务。
2.代码示例
主线程定义一个handle(mHandle),构造方法里面new一个callback,复写handleMessage方法,这
就表明当有信息来的时候,由handleMessage方法去执行
mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
//处理消息
if(msg.what == 1) {
Log.d("hanldeTest","object is -- > " + msg.obj);
}
return false;
}
});
子线程中,假设处理完了一些耗时操作,比如读写数据库,随后即可执行一下代码
Message message = mHandler.obtainMessage();
message.what = 1;
message.obj = "我是新消息!";
mHandler.sendMessage(message);
这样子一个发送,一个接受,就完成了就基本的handle使用,值得注意的是,上诉方法已经过期了
下面是最新的使用方法:
boolean test=new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
//更新ui处理,在耗时任务完成后
}
});
这里细心观察的小伙伴就会发现,参数里面有一个getMainLooper(),字面意思就是获得主looper对吧,那么looper是个啥?拿了有啥用?我们先以过期的方法去解释更方便
handle源码:
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这里有个值得的两个对象,mLooper,mQueue。当系统创建一个ActivityThread的时候,也创建了一个Looper,在looper里面有一个消息队列(其实是单链表结构的东西),Looper负责不断循环保持我们的程序不会结束,queue则负责接受消息,然后有handle去处理。我们一个线程只有一个looper,负责当前线程的不中断,但是handle可以有多个,所有的handle都依附于某个消息队列(没有队列你要搬运工干嘛对吧),而队列由looper创建,这也相当于handle间接依赖于looper了嘛~(看源码mQueue = mLooper.mQueue;)
因为系统一开始就创建好ui线程的时候也自动帮我们创建好了looper,也所以我们在主线程创建的时候可以不用关心handle具体依附于哪个looper。
但是如果在子线程中呢?子线程则没有这样好的待遇,它没有自动生成looper,所以我们在普通子线程中创建handle不指定好特定的looper就会报错,因为handle要好好依赖于一个消息队列,而消息队列由我们的looper产生的嘛~因此就有了new Handler((放一个looper过来!))这个方法,如
new Handler(getMainLooper())。
3注意点
下面说一下几个注意点,我在面试的时候看到面试官也会问错的问题。handle是如何实现异步的?
可能有的同学就会说,异步?就创建一个子线程啊!其实handle,runnable之类的并不会创建一个新线程!
1、handle可以在主线程中创建,而正在使用发送信息是在子线程,而不是handle自己new了一个子线程
2、handle创建的时候依赖于传入的looper,如果传入的looper是ui线程的looper,那么当在子线程调用的时候,handle发送的消息也是发送到ui线程的消息队列里面,由消息队列取出来再处理,所以才会有这样一个异步的操作。线程的looper一直在调用.loop方法,去查询消息队列有没有东西,有的话就取出来。
源码如下
public static void loop() {
final Looper me = myLooper();
......
//开始轮询,这个轮询可能阻塞
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......
msg.recycleUnchecked();
}
}
最后
看到这里你应该对handle处理消息是如何进行的吧,感谢各位看官~
xpl肖朋礼: 这是用c++吗?怎么运行不了呀?
别说我太单纯: 棒哥
别说我太单纯: 🔴收藏了.2021.1.7
陳傢兴: 谢谢
Chimoshi: 点赞关注收藏投币