最后
针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
-
Android前沿技术大纲
-
全套体系化高级架构视频
Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
} else {
//dispatchMesage后执行的println
//获取结束时间
final long endTime = System.currentTimeMillis();
mPrintingStarted = false;
//判断耗时是否超过阈值
if (isBlock(endTime)) {
notifyBlockEvent(endTime);
}
//最终会调用Stacksampler.stop()方法;
stopDump();
}
}
//判断是否超过阈值
private boolean isBlock(long endTime) {
return endTime - mStartTimestamp > mBlockThresholdMillis;
}
//回调监听
private void notifyBlockEvent(final long endTime) {
final long startTime = mStartTimestamp;
final long startThreadTime = mStartThreadTimestamp;
final long endThreadTime = SystemClock.currentThreadTimeMillis();
HandlerThreadFactory.getWriteLogThreadHandler().post(new Runnable() {
@Override
public void run() {
mBlockListener.onBlockEvent(startTime, endTime, startThreadTime, endThreadTime);
}
});
}
其中在startDump方法最终会调用Stacksampler.start()方法;stopDump最终会调用Stacksampler.stop()方法;相关方法如下:
Stacksampler
public void start() {
//在mRunable进行信息采集;
HandlerThreadFactory.getTimerThreadHandler().removeCallbacks(mRunnable);
//通过一个HandlerThread延时执行了mRunnable
HandlerThreadFactory.getTimerThreadHandler().postDelayed(mRunnable,
BlockCanaryInternals.getInstance().getSampleDelay());
}
public void stop() {
//取消handler消息,如果未超时就不会采集相关信息
HandlerThreadFactory.getTimerThreadHandler().removeCallbacks(mRunnable);
}
在开始进行msg.target.dispatchMessage(msg)消息分发前通过HandlerThread发送一个延时runable,在msg.target.dispatchMessage(msg)消息分发后会remove该runable,如果指定的时间消息分发没有完成,说明应用发生了卡顿,这之后开始执行mRunable,在mRunable进行相关信息采集及提示APP发生卡顿;以上就是BlockCanary监测卡顿的核心原理;
利用Choreographer监测APP卡顿
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染。开发者可以使用Choreographer#postFrameCallback设置自己的callback与Choreographer交互,你设置的FrameCallCack(doFrame方法)会在下一个frame被渲染时触发。理论上来说两次回调的时间周期应该在16ms,如果超过了16ms我们则认为发生了卡顿,我们主要就是利用两次回调间的时间周期来判断,
Choreographer.getInstance()
.postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long l) {
//移除消息
Handler.removeMessage();
//发送延时消息
Hnadler.sendMessageAtTime(…)
Choreographer.getInstance().postFrameCallback(this);
}
});
发送的延时消息在执行的时间没有被remove掉,说明发生了卡顿,这时候可以进行卡顿相关信息的采集,如果在渲染下一帧的时候该消息还没有被处理,这时候将该消息remove掉,此场景说明未发生卡顿;该检测卡顿的思想和BlockCanary类似;
最后,我们可以结合上述原理以及自己需求开发出一个适合自己的卡顿监测方案,也可以参考已有开源方案。
其它
为什么主线程Looper.loop进行消息分发耗时就代表APP卡顿?
答:为了保证应用的平滑性,每一帧渲染时间不能超过16ms,达到60帧每秒;如果UI渲染慢的话,就会发生丢帧,这样用户就会感觉到不连贯性,我们称之为Jank(APP卡顿);VSync信号由SurfaceFlinger实现并定时发送(每16ms发送),Choreographer.FrameDisplayEventReceiver收到信号后,调用onVsync方法组织消息发送到主线程处理。Choreographer主要功能是当收到VSync信号时,去调用使用通过postCallBack设置的回调函数,在postCallBack调用doFrame,在doFrame中渲染下一帧;FrameDisplayEventReceiver相关代码如下:
Choreographer.java
/**
-
FrameDisplayEventReceiver继承自DisplayEventReceiver接收底层的VSync信号开始处理UI过程。
-
VSync信号由SurfaceFlinger实现并定时发送。FrameDisplayEventReceiver收到信号后,
-
调用onVsync方法组织消息发送到主线程处理。这个消息主要内容就是run方法里面的doFrame了,
-
这里mTimestampNanos是信号到来的时间参数。
*/
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
mTimestampNanos = timestampNanos;
mFrame = frame;
// 发送Runnable(callback参数即当前对象FrameDisplayEventReceiver)到FrameHandler,请求执行doFrame
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
// 此处mHandler为FrameHandler,该Handler对应的Looper是主线程的Looper
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
在mHandler.sendMessageAtTime发送消息之后,最终会在主线程的Looper.loop()方法中调用msg.target.dispatchMessage(msg);Looper.loop相关代码可以参考在本文上边进行查看;然后在Handler.dispatchMeassange分发消息,如下所示:
Handler.java
public void dispatchMessage(Message msg) {
// Message的callback实际上就是Handler的post方法所传递的Runnable参数
// 这里首先检查是否有由Runnable封装的消息,如果有,首先处理;
if (msg.callback != null) {
handleCallback(msg);
} else {
// 其次处理mCallback
if (mCallback != null) {
// 如果mCallback的handleMessage方法返回true,那么handler中的handleMessage方法是不会被执行的
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
//在此执行FrameDisplayEventReceiver中的run方法,最终执行doFrame渲染下一帧;
message.callback.run();
}
通过以上流程可以发现,Android渲染每一帧都是通过消息机制来实现的,最终都会在主线Looper.loop()方法中开始渲染下一帧,因为Looper.loop方法在进行消息分发时是串行执行的,这样如果上一个消息分发时间过长即msg.target.dispatchMessage(msg)执行时间过长,就会导致在VSYNC到来时进行下一帧渲染延迟执行,就不能保证该帧在16ms内完成渲染,从而导致丢帧;所以主线程Looper.loop方法中msg.target.dispatchMessage(msg)执行时间过长就会导致APP卡顿;因此通过检测msg.target.dispatchMessage(msg)执行时间就可以检测APP卡顿;
Android消息机制的重要性:
1.在卡顿监测会用到消息机制;主要是发送一个延时消息来监测是否,在执行时间内没有remove该消息就代码APP发生卡顿;
2.ANR监测也是通过发送一个延时消息来监测是否发生ANR;ANR是APP卡顿的极端情况;
3.View监测事件是否长按也用到消息机制,在发生Down的时候会发送一个延时消息,在Up的时候会将该消息Remove掉,如果指定的时间没有发生UP就会触发长按事件;
4.Choreographer在渲染每一帧的时候也是通过发送一个消息,然后在Looper.loop中处理下一个消息时才会去渲染下一帧;
5.Activity生命周期的控制也是在ActivityThread发送不同的消息来切换Activity生命周期;
6.消息机制可以将一个任务切换到其它指定的线程,如AsyncTask;
以上这些场景都用到Android消息机制,还有很多其他未知的场景可能也会用到Android消息机制,所以消息机制在Android中具有很重要的地位;
参考资料
Blog in Chinese: BlockCanary.
Android Choreographer 源码分析 讲的很好很重要
作者:htkeepmoving
链接:https://www.jianshu.com/p/9e8f88eac490
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
写在最后
本次我的分享也接近尾声了,感谢你们在百忙中花上一下午来这里聆听我的宣讲,希望在接下来的日子,我们共同成长,一起进步!!!
最后放上一个大概的Android学习方向及思路(详细的内容太多了~),提供给大家:
对于程序员来说,要学习的知识内容、技术有太多太多,这里就先放上一部分,其他的内容有机会在后面的文章向大家呈现出来,不过我自己所有的学习资料都整理成了一个文档,一直在不断学习,希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!
Android架构师之路很漫长,一起共勉吧!
如果你觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
的支持!**
Android架构师之路很漫长,一起共勉吧!
如果你觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。
[外链图片转存中…(img-WhRRxgTb-1715660102566)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!