原文:ghcljx72eo.feishu.cn/docx/ROZKdu…
阅读SDK版别:31
运用发动流程
Activity发动流程
要害debug节点:
//左边 ActivithThread
//右侧 ActivityTaskManagerService>..>ActivityTaskSupervisor
//中继 debug:ClientTransaction.schedule>mclient.scheduleTransaction
//这儿是 mclient是 ApplicationThread,从这儿经过binder回到ActivithThread的
//父类 ClientTransactionHandler.scheduleTransaction>TransactionExecutor>
//TransactionExecutor担任解析ClientTransaction,分发回执到ATMS到音讯与
//调用ActivityThread的各个launch办法
//要注意TransactionExecutor.performLifecycleSequence中的switch根本只会进入ON_CREATE,其他的在各Launch
//办法中自己串联的
//回到左边 ActivithThread各Launch,创立activity,履行resume,发送idle音讯履行stop,destory等
从发动看要点:ActivivtyRecord在何时创立,
ActivityThread extends ClientTransactionHandler
下面都是 经过binder发送到ApplicationThread由它调用ActivityThread父类的 scheduleTransaction
最后在TransactionExecutor(ClientTransactionHandler)的 executeCallbacks,executeLifecycleState 中调用对应的 execute办法,分配到对应的 ActivityThread 的各个生命周期调用里
榜首次一个音讯: TopResumedActivityChangeItem
ActivityTaskSupervisor:mAtmService.getLifecycleManager().scheduleTransaction(binder:ApplicationThread, appToken,
TopResumedActivityChangeItem.obtain(onTop));
ClientLifecycleManager.scheduleTransaction{
ClientTransaction clientTransaction = transactionWithCallback(client, activityToken, callback);
{new ClientTransaction(client=ApplicationThread)}
}
clientTransaction.schedule()
第2次一个音讯: PauseActivityItem
ActivityTaskSupervisor:mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately));
第三次 2个 音讯:launch and resume
ActivityTaskSupervisor:
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
//还有一个变量:mLifecycleStateRequest:ResumeActivityItem
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
第四次一个音讯:TopResumedActivityChangeItem
ActivityTaskSupervisor:
ActivityRecord.scheduleTopResumedActivityChanged{
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
TopResumedActivityChangeItem.obtain(onTop));
}
第五个音讯 : StopActivityItem
ActivityTaskSupervisor:
ActivityTaskSupervisor.activityIdleInternal>processStoppingAndFinishingActivities>
ActivityRecord.stopPossible{
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
StopActivityItem.obtain(configChangeFlags));
}
要点关注ActivityThread.handleXXX办法:
handleReLaunchActivity>
performDestroyActivity>
r.activity.retainNonConfigurationInstances();//保存 viewmodel等信息传递到新Activity
handleLaunchActivity>
unscheduleGcIdler();//撤销在后台承受GC的音讯
WindowManagerGlobal.initialize();//WMS 初始化
performLaunchActivity>
newActivity//反射创立 activity
makeApplicationif: (mApplication != null) return mApplication;
activity.attach>
attachBaseContext
new PhoneWindow()
if (theme != 0) {
activity. setTheme(theme) ;
}
if (r.isPersistable()) {// 区分耐久化,调用onCreat
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
handleResumeActivity>
unscheduleGcIdler();
performResumeActivity>
activity.performResume>
dispatchActivityPreResumed//大局callback 回调
performStart/performRestart
mInstrumentation.callActivity OnResume (this);
mFragments.dispatchResume();
dispatchActivityPostResumed();大局callback 回调
if (r.window == null && !a.mFinished && willBeVisible) >//不考虑 onCreate中setContrentView触发了Window绑定
r.window = r.activity.getWindow();//PhoneWindow
View decor = r.window.getDecorView();
ViewManager wm = a.getWindowManager();//WindowManagerGlobal
wm.addView(decor, l)>//完结 viewRootImpl 与DecorView相关
Root = new ViewRootImpl()
root.setView(view:DecorView)>
requestLayout();//触发榜首个大略布局
Looper.myQueue().addIdleHandler(new Idler())>;//刺进一条Idler音讯
ac.activityIdle(a.token, a.createdConfig, stopProfiling)>//给一切没有
ActivityClientController.activityIdle>//ActivityClientController是一个 IBinder
activityIdleInternal>
mHandler.removeMessages( IDLE_TIMEOUT_MSG , r);
mHandler.removeMessages( LAUNCH_TIMEOUT_MSG );
processStoppingAndFinishingActivities>
if (r.isInHistory()) {
if ( r.finishing ) {
// TODO(b/137329632): Wait for idle of the right activity, not just any.
r.destroyIfPossible(reason);
} else {
r.stopIfPossible();>
}
}
.. r.destroyImmediately(reason);
r.stopIfPossible();>
mAtmService.getLifecycleManager().scheduleTransaction( StopActivityItem );
r.destroyImmediately(reason);>
mAtmService.getLifecycleManager().scheduleTransaction( DestroyActivityItem )
在resume之后发送idle音讯,触发 stop
同时设置Idle超时音讯,假如 10s没有履行则会自动再次触发 activityIdleInternal
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
StopActivityItem.obtain(configChangeFlags));
mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);//stop 超时时刻 11s
mStopTimeoutRunnable:Slog.w(TAG, "Activity stop timeout for " + ActivityRecord.this);
notifyAppStopped();//运用停止运转
//怎么撤销stopTimeOut音讯 需求去handleTopActivity看
关于 IdleHandler的履行时机
Looper.myQueue().addIdleHandler(new Idler())//mIdleHandlers.add()
MessageQueue.next()>MessageQueue:链表
每次依据时刻查找满意履行的message
此次时刻上没有要履行的message时,履行截至目前存在的悉数Idle音讯
轮训下一个时刻可履行的音讯
handleStopActivity
performStopActivityInner>
performPauseActivityIfNeeded //再次承认puase了没
callActivityOnStop>
callActivityOnSaveInstanceState // targetSdkVersion<28
activity.performStop>
dispatchActivityPreStopped
mFragments.dispatchStop()
mInstrumentation.callActivityOnStop
dispatchActivityPostStopped
callActivityOnSaveInstanceState(r) // targetSdkVersion>=28
if(targetSdkVersion>11){
QueuedWork.waitToFinish()//等候完结悉数finish runnable
}
pendingActions.setStopInfo(stopInfo);//这儿是要点
//-----怎么回传到 ATMS 去 removeStopTimeOut音讯的逻辑
TransactionExecutor中对一切的 ClientTransactionItem 调用
item.execute(mTransactionHandler:ClientTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
回到 ActivityThread.reportStop(mPendingActions)>mH.post(pendingActions.getStopInfo());
履行 PendingTransactionActions.StopInfo 的run办法 通知ATMS
ActivityClient.getInstance().activityStopped(
mActivity.token, mState, mPersistentState, mDescription);
//binder:ActivityClientController>ActivityRecor.activityStopped>removeStopTimeOut
关于waitToFinish导致ANR的问题:在SharedPreferenceImpl中会调用 QueuedWork.addFinisher(sp 内存写入磁盘的runnable),单低于26(8.0)的SharedPreferenceImpl的完结性能较差,每次都是悉数写入磁盘,有大量SP数据需求写入时,触发 finish 就会导致ANRq
handleDestroyActivity>
performDestroyActivity>
if (getNonConfigInstance) {r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances()}
mInstrumentation.callActivityOnDestroy(r.activity);
cleanUpPendingRemoveWindows>
WindowManagerGlobal.closeAll()>
ViewRootImpl.die>
//解绑输入时刻,毁掉硬件渲染器,dispatchDetachedFromWindow,解绑 decorView
WindowManagerGlobal.getInstance().doRemoveView(this);//移除ViewRootImpl
事情:
榜首块:承受native事情
WindowInputEventReceiver extends InputEventReceiver
Native>
InputEventReceiver.dispatchInputEvent>WindowInputEventReceiver.onInputEvent>ViewRootImpl.enqueueInputEvent>ViewRootImpl.doProcessInputEvents>....>processPointerEvent>View.dispatchPointerEvent>DecorView.dispatchTouchEvent>mWindow.CallBack.dispatchTouchEvent | super(ViewGroup).dispatchTouchEvent {Activity 能够截胡或消费后放行,但事情是从Native直接传递到ViewRootImpl的},
默认是走Activity dispatchTouchEvent,但会优先 回到View上,假如重写了能够自己截胡或许消费完再调super,只重写 onTouchEvent不重写dispatchTouchEvent 则在View消费后才有或许获取到事情
activity代码:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) { // 这儿的调用链条:IphoneWindow>mDecorView.superDispatchTouchEvent>ViewGroup.dispatchTouchEvent()
return true;
}
return onTouchEvent(ev);
}
Window.Callback.dispatchTouchEvent>Activity.dispatchTouchEvent>DOWN:onUserInteraction,Activity.onTouchEvent)
ViewGroup.dispatchTouchEvent>
第二块:ViewGroup
在Down事情或已有事情消费方针时
ViewGroup.disallowIntercept:false>ViewGroup.onInterceptTouchEvent
ViewGroup.disallowIntercept:true>intercepted = false
假如子view没有为父view设置DisallowIntercept,就查看父view自己是否在onInterceptTouchEvent自己阻拦
第三块:ViewGroup if (!canceled && !intercepted) {}
未撤销,父View也未阻拦,处于初始事情,遍历childView 寻找消费方针:dispatchTransformedTouchEvent>addTouchTarget>
child.dispatchTouchEvent>realView.dispatchTouchEvent>onTouch | onTouchEvent
第四块:ViewGroup if(mFirstTouchTarget == null)
找不到消费方针丢给 父类:View.dispatchTouchEvent 处理
第五块:View
将后续事情传给上面找到的TargetView进行消费
布局:
榜首块:onCreate:Activity的window 创立
ActivityThread.handleLaunchActivity>...>activit.attach>attachBaseContext,mWindow = PhoneWindow(ActivityClientRecord.mPendingRemoveWindow)
if(mPreserveWindow) mDecorView 将被复用否则 new PhoneWindow
UserActivity.setContentView>AppCompatActivity.setContentView>:initViewTreeOwners>getWindow().getDecorView
>PhoneWindow.getDecorView>PhoneWindow.installDecor>:createDecorView,mDecor.setWindow(this);
创立DecorView完结window与 DecorView的相关。DecorView父类是FrameLayout
DecorView创立时会出真话导航栏背景色,半透明状况栏颜色,导航栏进出动画等, AppCompatActivitysetContentView>:
getDelegate.setContentView>AppCompatDelegateImpl.setContentView>:ensureSubDecor()再次确保decorView已创立好
第二块:onResume
ActivityThread.handleResumeActivity>:WindowManager(WindowManagerGlobal).addView(decorView:window.getDecorView)>:
root = new ViewRootImpl(view.getContext(), display)
global.mViews.add(decorView)//大局保存
global.mRoots.add(root)//大局保存
root.setView(decorView..)//完结ViewRootImpl 与DecorView 相关>:
requestLayout()//进行首次布局,确保承受体系事情前有布局
mWindowSession.addToDisplayAsUser(InputChannel)
mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
Looper.myLooper());//这儿没看懂,没到怎么被回调
view.assignParent(this);将ViewRootImpl 指定为DecorView的ParentView
requestLayout()>:checkThread(指判断是否为创立线程),scheduleTraversals()
scheduleTraversals()>mChoreographer.postCallback(horeographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
mTraversalRunnable.run> doTraversal> :
performMeasure
performLayout
performDraw
自定义View嵌套滑动冲突
核心是结合多个 NestedScrollingParent,NestedScrollingChild 处理好上下游滑动事情的消费逻辑
几年前写的一个支持逃跑子View的下拉刷新库:github.com能够让我快速捡起对滑动事情处理的常识。
ANR
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
println("eventView:click")
Thread.sleep(10*10000)
return super.dispatchTouchEvent(ev)
}
上面的代码在小米K30 上 假如没有新的体系音讯履行获取反馈,则不会触发 处理超时ANR
ROOM厂商会优化ANR的体验,模拟器会ANR
官方文档:
- 输入调度超时:假如您的运用在 5 秒内未响应输入事情(例如按键或屏幕触摸)。
-
履行服务:假如运用声明的服务无法在几秒内完结
Service.onCreate()
和Service.onStartCommand()
/Service.onBind()
履行。 -
未调用 Service.startForeground() :假如您的运用运用
Context.startForegroundService()
在前台发动新服务,但该服务在 5 秒内未调用startForeground()
。 -
intent 播送:假如
BroadcastReceiver
在设定的一段时刻内没有履行结束。假如运用有任何前台 activity,此超时期限为 5 秒。
其他实践细节:
前台播送5s,后台播送60s
诊断ANR
- 运用在主线程上十分缓慢地履行涉及 I/O 的操作。
- 运用在主线程进步行长时刻的计算。
- 主线程在对另一个进程进行同步 binder 调用,而后者需求很长时刻才干回来。
- 主线程处于阻塞状况,为产生在另一个线程上的长操作等候同步的块。
- 主线程在进程中或经过 binder 调用与另一个线程之间产生死锁。主线程不只是在等候长操作履行结束,而且处于死锁状况。如需了解详情,请参阅维基百科上的死锁。
总结:
除了API调用的逻辑错误外,主要是在主线程有长时刻履行的代码或锁,阻塞了后续体系or用户的操作,体系会发出ANR提示
ANR管理:developer.android.com/topic/perfo…
阅读橘子树其他文章:橘子树的个人写作记录