基于android studio 的ADM对卡顿,耗时方法的检测
2018-10-25 本文已影响144人
古宇强
1.Activity间的跳转耗时接近两秒了
打开android设备模拟器
选中项目所在进程
点击ok后在手机上开始运行卡顿的界面
点击后停止获取信息,自动生成.trace文件
放大方便分析
2.可以发现,红框中的就是自己项目中的代码,耗时占了总耗时的73.9%
3.在项目中修改后达到了可接受的打开时间
4.往空闲消息队列中添加信息,这类信息会在主线程空闲时才会被取出来处理,一般用在Activity的初始化方法onCreate()中,在queueIdle()方法添加不会回影响Activity正常初始化的耗时操作,此方法返回false会在执行完后把这个消息从空闲消息队列中删除
在Activity的onCreate()方法中
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler(){
@Override
public boolean queueIdle() {
//微信,qq分享辅助类的初始化就是一个耗时操作,里面涉及到了反射
WXUtil.regToWx(context);
mTencent = Tencent.createInstance(Constant.QQ_APP_ID, getApplication());
return false;
}
});
扩展:源码阅读(MessageQueue的next():消息循环)
Message next() {
// 当消息循环已经退出或被释放的时候,直接返回null
// 如果应用程序在退出后尝试重新启动一个looper,就可能会发生这种情况
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {//死循环
//将当前线程中的任何阻塞的binder命令刷新到cpu中执行,在执行可能导致长时间阻塞的操作前调用是非常有用的,可以确保任何挂起的对象引用被释放,防止进程持有一个对象的时间超过它所需要的
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//消息死循环不会崩溃的原因
nativePollOnce(ptr, nextPollTimeoutMillis);
//同步代码块
synchronized (this) {
// 尝试检索下一条信息,如果有就返回
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. 在消息队列中查找下一个异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//如果下一条消息尚未准备好。设置超时唤醒
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 如果准备好了就获取消息.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// 没有异步消息了
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// 如果第一次空闲,则获取可运行消息数
// 空闲消息只会在消息队列为空或者队列第一个消息将要被处理时处理
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
//容量只有四个
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
//只有在第一次迭代中才到达这个代码块
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
//当返回值keep为false时,从空闲列表中移除
mIdleHandlers.remove(idler);
}
}
}
// 保证了空闲列表中的消息只处理一次.
pendingIdleHandlerCount = 0;
// 在调用空闲处理程序时,可能已经传递了一个新消息,因此可以返回并再次查找挂起的消息,而不必等待
nextPollTimeoutMillis = 0;
}
}