android子线程handler
A. android handler是在主线程中吗
Handler对拍颂历象一般是在主线程中创建的,在子线程中执行耗时操樱凳作发送消息,推袭搜荐你看这篇博客http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html 讲解很清晰
B. Android在子线程用handler发送的消息,主线程是怎么loop到的
因为你是在主线程创建的handler实例,比如你是这样实例化handler
然后调用looper.loop();就开始了消息循环。这就是为什么在主线程发消息住线程还能收到消息的原因。因为发送消息的实例是在主线程实例化的就有了主线程的looper。
C. 能讲讲Android的Handler机制吗
Android的Handler机制是通俗讲为了互相发消息,一般是子线程给主线程发消息完成相应操作。
安卓中最常见的操作是子线程操作完事后得到数据想更新UI,安卓有规定不允许在子线程中刷新UI,所以Handler出现了。
使用和理解大致步骤。
创建全局Handler对象handler,然后在主线程中初始化它(一般在oncreate中),把它的handmessage里面的方法重写,这个方法是收到子线程发给它的消息后执行的逻辑。
在子线程中获取数据,调用handler.sendmessage,把要发的消息放在message中。message会添加到Messagequue(消息队列中,handler创建就带的)。
3.对象handler被创建和初始化的时候,系统自动会启动Handler.looper,也就是一个消息轮询器,它不断的去查看有没有消息进入到Messagequue(消息队列中),有就取出交给handler的handmessage去处理。//这段逻辑是系统自动执行,理解就行。*纯手打,不骗人~~~
D. Android——消息分发机制
什么是 Handler 机制 ?
Handler 机制是 Android 中用于 线程间通信 的一套通信机制。
为什么是 Handler ?Handler 机制为什么被那么多次的提及 ?
从Android4.0开始,Android 中网络请求强制不允许在主线程中操作,而更新UI的操作则不允许在子线程中执行。当在子线程中执行网络请求,拿到服务器返回的数据之后,要更新UI。由于系统的要求,势必会产生一种矛盾:数据在子线程,更新UI要在主线程。此时我们必须要把数据返回到主线程中才行,Handler机制应运而生。
Android 中针对耗时的操作,放在主线程操作,轻者会造成 UI 卡顿,重则会直接无响应,造成 Force Close。同时在 Android 3.0 以后,禁止在主线程进行网络请求。
针对耗时或者网络操作,那就不能在主线程进行直接操作了,需要放在子线程或者是工作线程中进行操作,操作完成以后,再更新主线程即 UI 线程。这里就涉及到一个问题了,在子线程执行完成以后,怎么能更新到主线程即 UI 线程呢,针对以上问题,就需要用到 Android 的消息机制了,即: Handler, Message, MessageQueue, Looper 全家桶
Handler机制中最重要的四个对象
Handler的构造方法:
Looper :
Handler的使用:
MessageQueue:
Looper.loop()
Handler.dispatchMessage()
handler导致activity内存泄露的原因:
handler发送的消息在当前handler的消息队列中,如果此时activity finish掉了,那么消息队列的消息依旧会由handler进行处理,若此时handler声明为内部类(非静态内部类),我们知道内部类天然持有外部类的实例引用,这样在GC垃圾回收机制进行回收时发现这个Activity居然还有其他引用存在,因而就不会去回收这个Activity,进而导致activity泄露。
假如在子线程执行了耗时操作,这时用户操作进入了其他的 acitvity, 那么 MainActivity 就会被内存回收的,但是这个时候发现 Handler 还在引用着 MainActivity,内存无法及时回收,造成内存泄漏。
Handler 防止内存泄漏常见方法:
为什么通过 Handler 可以把子线程的结果通知或者携带给 UI 线程 ?
这里的 Handler 指的是主线程的 Handler ,同时与 Handler 配套的 Looper , MessageQueue 是在 UI 线程初始化的,所以在子线程中调用 Handler 发送消息可以更新 UI 线程。
Looper 在 UI 线程源码, 在 ActivityThread 类:
E. Android中Handler的主要作用是什么通俗点,初学。
Handler的使用主要是android中无法在主线程(即UI线程)中访问网络、无法在子线程中访问UI线程元素。
一般是在子线程中访问网络,然后使用Handler发送message通知主线程处理UI更新操作
F. Android Handler那些事儿,消息屏障IdelHandlerANR
Handler 是Android SDK中用来处理异步消息的核心类,子线程可以通过handler来通知主线程进行ui更新。
备注:本文源码截图 基于Android sdk 28
Handler机制 消息发送主要流程如图
应用程序启动后,zygote fork一个应用进程后,和普通java程序一样,程序会首先执行ActivityThread中的main函数。在main函数中,程序首先会创建Looper对象并绑定到主线程中,然后开启loop循环。(ps:主线程loop循环不能退出)
在prepareMainLooper方法中,最终会创建Looper,MessageQueue对象 以及创建native层MessageQueue对象。
使用Handler.sendMessageXXX或这 postDedayXXX发送消息后,最终会调用到SendMessageAtTime方法中。
然后调用MessageQueue.enqueueMessage将消息存到消息队列中。
存入消息后,然后通过调用native方法 唤醒主线程进行消息处理。
当应用程序启动,做完一些必要工作之后,便会开启Loop循环,除非系统异常,否则该循环不会停止。loop循环中,主要做两件事,第一,从消息队列中取消息。第二,进行消息分发处理。
MessageQueue.next() 方法 通过调用 native方法 nativePollOnce(ptr, nextPollTimeoutMillis)实现无消息处理时,进入阻塞的功能。
当nextPollTimeoutMillis 值为0时,该方法会立刻返回;
当nextPollTimeoutMillis 值为-1时,该方法会无限阻塞,直到被唤醒;
当nextPollTimeoutMillis 值大于0时,该方法会将该值设置为超时时间,阻塞到达一定时间后,返回;
在loop循环中 ,通过调用 msg.target.dispatchMessage(msg) 进行消息的分发处理
使用当前线程的MessageQueue.addIdleHandler方法可以在消息队列中添加一个IdelHandler。
当MessageQueue 阻塞时,即当前线程空闲时,会回调IdleHandler中的方法;
当IdelHandler接口返回false时,表示该IdelHandler只执行一次,
a,延迟执行
例如,当启动Activity时,需要延时执行一些操作,以免启动过慢,我们常常使用以下方式延迟执行任务,但是在延迟时间上却不好控制。
其实,这时候使用IdelHandler 会更优雅
b,批量任务,任务密集,且只关注最终结果
例如,在开发一个IM类型的界面时,通常情况下,每次收到一个IM消息时,都会刷新一次界面,但是当短时间内, 收到多条消息时,就会刷新多次界面,容易造成卡顿,影响性能,此时就可以使用一个工作线程监听IM消息,在通过添加IdelHandler的方式通知界面刷新,避免短时间内多次刷新界面情况的发生。
在Android的消息机制中,其实有三种消息: 普通消息、异步消息及消息屏障。
消息屏障 也是一种消息,但是它的target为 null。可以通过MessageQueue中的postSyncBarrier方法发送一个消息屏障(该方法为私有,需要反射调用)。
在消息循环中,如果第一条消息就是屏障消息,就往后遍历,看看有没有异步消息:
如果没有,则无限休眠,等待被唤醒
如果有,就看离这个消息被触发时间还有多久,设置一个超时时间,继续休眠
异步消息 和普通消息一样,只不过它被设置setAsynchronous 为true。有了这个标志位,消息机制会对它有些特别的处理,我们稍后说。
所以 消息屏障和异步消息的作用 很明显,在设置消息屏障后,异步消息具有优先处理的权利。
这时候我们回顾将消息添加到消息队列中时,可以发现,其实并不是每一次添加消息时,都会唤醒线程。
当该消息插入到队列头时,会唤醒该线程;
当该消息没有插入到队列头,但队列头是屏障,且该消息是队列中 靠前的一个异步消息,则会唤醒线程,执行该消息;
调用MessageQueue.removeSyncBarrier 方法可以移除指定的消息屏障
ANR 即 Application Not Response, 是系统进程对应用行为的一种监控,如果应用程序没有在规定时间内完成任务的话,就会引起ANR。
ANR类型
Service Timeout : 前台服务20s, 后台服务200s
BroadcastQueue Timeout : 前台广播 10s,后台广播60s
ContentPrivider Timeout : 10s
InputDispatching Timeout : 5s
比如,在启动一个服务时, AMS端通过应用进程的Binder对象创建Service, 在scheleCreateService()方法中 会调用到当前service的onCreate()生命周期函数;
bumpServiceExecutingLocked()方法内部实际上会调用到scheleServiceTimeoutLocked()方法,发送一个ActivityManagerService.SERVICE_TIMEOUT_MSG类型消息到AMS工作线程中。
消息的延时时间,如果是前台服务,延时20s, 如果是后台服务,延时200s;
如果Service的创建 工作在 上诉消息的延时时间内完成,则会移除该消息,
否则,在Handler正常收到这个消息后,就会进行服务超时处理,即弹出ANR对话框。
复杂情况下,可能会频繁调用sendMessage 往消息队列中,添加消息,导致消息积压,造成卡顿,
1,重复消息过滤
频繁发送同类型消息时,有可能队列中之前的消息还没有处理,又发了一条相同类型的消息,更新之前的数据,这时候,可以采用移除前一个消息的方法,优化消息队列。
2,互斥消息取消
在发送消息时,优先将消息队列中还未处理的信息已经过时的消息 移除,优化队列
3,队列优化-复用消息
创建消息时,优先采用之前回收的消息,避免重复创建对象,引起GC
完~
(如果错误或不足,望指出, 大家共同进步)