Ⅰ 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
完~
(如果错误或不足,望指出, 大家共同进步)
Ⅱ 如何关闭android中的HandlerThread
android 中的HandlerThread包含了android中的消息处理机制必须的looper,当你启动这个线程的时候,就会闯进looper,并开启消息处理的循环。
跟其它线程一样,HandlerThread是可不可以直接stop掉的,不过经过本人测试,你可以调用:getLooper().quit();来退出这个线程,其实原理很简单,就是改变在消息循环里面标志位,退出整个while循环,使线程执行完毕。
部分 测试代码如下:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv_name = (TextView) findViewById(R.id.tv_name);
btn_name = (Button) findViewById(R.id.btn_name);
Log.i(TAG, "==================main thread:" + Thread.currentThread().getName());
final HandlerThread thread = new HandlerThread("handlerThread");
thread.start();
final MyHandler handler = new MyHandler(thread.getLooper());
btn_name.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {
handler.sendEmptyMessage(1);try {Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();}thread.getLooper().quit();}});}
class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);}@Overridepublic void handleMessage(Message msg) {
Log.i(TAG, "==================" + Thread.currentThread().getName());
//tv_name.setText("hello, this is the first message from handler");
不过要注意:要想更新界面内容,还是需要使用界面的Looper,不然的话还是会抛错误,还是那句话,所有跟改变界关的操作,都得通过界面的Looper来执行
Ⅲ android handler是不是唯一的
前段时间在工作的时候碰见一个问题,就是要待机时在设定的时间内执行操作,开始并没有意识到问题的严重,后来尝试很多办法没有成功,最后也是在网上找到解决办法,在此稍作总结,希望能对大家有所帮助,不足之处还望大家指正。
1Android中的handler、timer、thread、在待机时都会停止运行,所设定的时间会在待机结束后继续计算。所以如果想在Android待机时运行某些操作,使用以上几种方法是不可行的。
2Android中有一个Alarmmanager对象,可以使用该对象执行待机时的操作。具体设置的方法如下:
2.1设置闹铃的类型
AlarmManager.RTC,硬件闹钟,不唤醒手机(也可能是其它设备)休眠;当手机休眠时不发射闹钟。
AlarmManager.RTC_WAKEUP,硬件闹钟,当闹钟发躰时唤醒手机休眠;
AlarmManager.ELAPSED_REALTIME,真实时间流逝闹钟,不唤醒手机休眠;当手机休眠时不发射闹钟。
AlarmManager.ELAPSED_REALTIME_WAKEUP,真实时间流逝闹钟,当闹钟发躰时唤醒手机休眠;
AlarmManager.POWER_OFF_WAKEUP:能唤醒系统,他是一种关机闹铃,就是说设备在关机状态下也可以唤醒系统,所以我们把它称为关机闹铃。
RTC闹钟和ELAPSED_REALTIME最大的差别就是前者可以通过修改手机时间触发闹钟事件,后者要通过真实时间的流逝,即使在休眠状态,时间也会被计算。
2.2设置闹铃的开始时间
如果使用ELAPSED_REALTIME或者ELAPSED_REALTIME_WAKEUP类型应该调用SystemClock.elapsedRealtime()获取相对时间在加上你设定的延迟时间
如果使用RTC或者RTC_WAKEUP类型应该调用System.currentTimeMillis()获取从1970.1.1号以来的时间在加上你设定的延迟时间
2.3pendingintent
一个PendingIntent对象,表示到时间后要执行的操作。PendingIntent与Intent类似,可以封装Activity、BroadcastReceiver和Service。
但与Intent不同的是,PendingIntent可以脱离应用程序而存在。
接触Android没几天,不太了解。
本来写好的一个应用在无意中发现,待机的时候,应用中的一个线程停止了运行。
这个线程是每隔一分钟上传一个数据到服务器上。
我当时测试的时候,没想过待机(接开关键)下的情况是怎样的,现在发现,只要手机一进入待机状态,这个线程就停止工作了。
不过有一个奇怪的现象,因为我的应用中同时启动了三个线程。
一个负责每隔一分钟上传一个数据,当待机的时候,这个线程暂停运行,当手机不待机的时候,马上复活。
一个负责接收服务器发过来的UDP数据包,这个线程倒是不受待机的影响,当有数据来的时候,可以正常处理。
难道是因为datagramSocket.receive(datagramPacket);阻塞的原因?
public void run()
{
while(true)
{
datagramSocket.receive(datagramPacket); //阻塞
}
}
到网上搜索了一下,看到别人说的:
实验1:使用Java.util.Timer
当连接USB线进行调试时,会发现一切工作正常,每5秒更新一次界面,即使是按下电源键,仍然会5秒触发一次。
当拔掉USB线,按下电源键关闭屏幕后,过一段时间再打开,发现定时器明显没有继续计数,停留在了关闭电源键时的数字。
实验2:使用AlarmService:
2.1通过AlarmService每个5秒发送一个广播,setRepeating时的类型为AlarmManager.ELAPSED_REALTIME。
拔掉USB线,按下电源键,过一段时间再次打开屏幕,发现定时器没有继续计数。
2.2setRepeating是的类型设置为AlarmManager.ELAPSED_REALTIME_WAKEUP
拔掉USB线,按下电源键,过一点时间再次打开屏幕,发现定时器一直在计数。
如此看来,使用WAKEUP才能保证自己想要的定时器一直工作,但是肯定会引起耗电量的增加。
我最后自已写了一个Service类,然后使用AlarmService每隔一分钟执行一次,在待机的时候也能正常运行。
Ⅳ 如何终止Android Handler 中的消息处理
终止Android Handler 中的消息处理的办法:
首先你可以放到线程中去执行,这个应该是个耗时操作,放到UI线程中,程序会假死。
然后你可以通过handler去启动这个线程来执行这个方法,如果取消的话,在发给handler一个消息,让handler再去停止这个线程。
Ⅳ Android的handler机制的原理
Android的handler机制的原理分为异步通信准备,消息发送,消息循环,消息处理。
1、异步通信准备
在主线程中创建处理器对象(Looper)、消息队列对象(Message Queue)和Handler对象。
2、消息入队
工作线程通过Handler发送消息(Message) 到消息队列(Message Queue)中。
3、消息循环
消息出队: Looper循环取出消息队列(Message Queue) 中的的消息(Message)。
消息分发: Looper将取出的消息 (Message) 发送给创建该消息的处理者(Handler)。
4、消息处理
处理者(Handler) 接收处理器(Looper) 发送过来的消息(Message),根据消息(Message) 进行U操作。
handler的作用
handler是android线程之间的消息机制,主要的作用是将一个任务切换到指定的线程中去执行,(准确的说是切换到构成handler的looper所在的线程中去出处理)android系统中的一个例子就是主线程中的所有操作都是通过主线程中的handler去处理的。
Handler的运行需要底层的 messagequeue和 looper做支撑。
Ⅵ android 关于Handler终止问题
你的判断语句有问题,相当于移除了消息又添加了消息,加一个else应该就能解决。
if(progress>=stop){
mHandler.removeMessages(MSG_PROGRESS_UPDATE);
}else{
mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_UPDATE,30);
}
Ⅶ android应用关闭了 销毁了 但是fragment里边的handler还在运行 怎么回事
1、不要直接将Fragement写在XML文件里,这样会导致Fragment对象无法销毁,产生内存溢出。在代码动态的new 和add Fragement才是正确的做法。 2、使用抽屉方法,在XML文件里放两个LinearLayout,然后在代码中将Fragment加进这两个LinearLayout中
Ⅷ 安卓定时器Handler如何关闭
{
publicTimeCounts(longmillisInFuture,longcountDownInterval){
super(millisInFuture,countDownInterval);//参数依次为总时长,和计时的时间间隔
}
@Override
publicvoidonFinish(){//计时完毕时触发
}
@Override
publicvoidonTick(longmillisUntilFinished){//计时过程显示
//倒计时数可以写在这儿
}
}
TimeCounts timeCounts = new TimeCounts(30000, 1000);//总时长30s,间隔1s
timeCounts.start();//倒计时开始
timeCounts.cancel();//取消倒计时
Ⅸ android中,怎么停止handler
Android四大组件如人体四肢,Handle如人体中的血液。它贯穿于各个组件,连Activity的onCreat方法都是由它调用的。你让它停下来?我真的很好奇: 你的程序怎么跑???