前言
这段时间, leader 安排的任务进行 Android 插件化, 热修复相关的调研, 对于插件化和热修复涉及到的核心技术点, 在于对于类装载, 资源装载的认识还有对于启动流程的熟悉, 带着该任务, 于是有了接下来, 一系列的文章, 从进程启动, Activity 显示, Dex 装载, 资源装载, 最后主流几个插件化, 热修复源码实现的分析本篇先从进程的启动, 到一个 Activity 的显示流程出发分析
启动一个进程
在 Anroid 中, 进程是一个运行组件的容器, 系统运行一个组件的时候, 启动包含它的进程, 当组件不再使用, 进程会被关闭 AMS 负责对应应用进程的启动
开启一个新的进程, 在 AMS 中首先调用 addAppLocked
- final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated, String abiOverride) {
- ProcessRecord app;
- if (!isolated) {
- // 从已经开启记录下的进程中查找进程记录
- app = getProcessRecordLocked(info.processName, info.uid, true);
- } else {
- app = null;
- }
- //app 为空的时候, 创建一个新的进程, 同时更新内部进程管理结构
- if (app == null) {
- app = newProcessRecordLocked(info, null, isolated, 0);
- updateLruProcessLocked(app, false, null);
- updateOomAdjLocked();
- }.....
- if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
- app.persistent = true;
- app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
- }
- if (app.thread == null && mPersistentStartingProcesses.indexOf(app) <0) {
- mPersistentStartingProcesses.add(app);
- // 调用进程的启动方法, 启动一个新的进程
- startProcessLocked(app, "added application", app.processName, abiOverride, null
- /* entryPoint */
- , null
- /* entryPointArgs */
- );
- }
- return app;
- }
首先会从已经启动的进程中查找相应的进程信息, ProcessRecord, 如果不存在则会创建一个出来, 然后调用 startProcessLocked 方法, 来开启一个新的进程
- private final void startProcessLocked(ProcessRecord app, String hostingType,
- String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
- // 启动应用
- ....
- Process.ProcessStartResult startResult = Process.start(entryPoint,
- app.processName, uid, uid, gids, debugFlags, mountExternal,
- app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
- app.info.dataDir, entryPointArgs);
- ....
- // 发送定时消息, 如果 App 的启动超时, 则会 ANR
- synchronized (mPidsSelfLocked) {
- this.mPidsSelfLocked.put(startResult.pid, app);
- if (isActivityProcess) {
- Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg, startResult.usingWrapper
- ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
- }
- }
- ....
- }
进程的开启调用的是 Process 的 start 方法
- public static final ProcessStartResult start(final String processClass,
- final String niceName,
- int uid, int gid, int[] gids,
- int debugFlags, int mountExternal,
- int targetSdkVersion,
- String seInfo,
- String abi,
- String instructionSet,
- String appDataDir,
- String[] zygoteArgs) {
- try {
- return startViaZygote(processClass, niceName, uid, gid, gids,
- debugFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, zygoteArgs);
- } catch (ZygoteStartFailedEx ex) {
- }
- }
start 方法中, 通过调用 startViaZygote, 通过 zygote 进程来开启一个新的进程
- private static ProcessStartResult startViaZygote(final String processClass, ...){
- // 配置通过 Zygote 启动的参数, 最终通过 socket 写入到 Zygote 进程, 来开启一个新的进程
- }
方法的具体执行是通过 socket 将进程的启动信息, 写入到 zygote 中, 然后通过其启动一个新的进程, 同时对于该进程, 也指定了一个类作为执行的入口类, 这个类就是 ActivityThread
entryPoint = "android.app.ActivityThread";
在 start 方法中的 entryPoint, 这个就是进程启动后要执行的 Java 类, 进程启动后, 所有操作就转交到 ActivityThread 的执行, 因此, 这个类也是整个应用执行的核心这个类首先被执行的是其 main 函数
- public static void main(String[] args) {
- ...
- Looper.prepareMainLooper();
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- Looper.loop();
- ....
- }
ActivityThread 的 attach 方法
- private void attach(boolean system) {
- ......
- final IActivityManager mgr = ActivityManagerNative.getDefault();
- try {
- // 调用 AMS 的 attachApplication 方法, 传递 ApplicationThread 进去
- mgr.attachApplication(mAppThread);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- .....
- }
Ams 的 attachApplication 方法会调用到 Ams 的
attachApplicationLocked
方法,
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,...)
这个方法的主要功能是创建出应用程序中的各种对象, 是比较核心的方法
- private void handleBindApplication(AppBindData data) {
- // 注册当前 UI 线程到 Runtime 作为一个敏感线程
- VMRuntime.registerSensitiveThread();
- // 设置进程的启动时间
- Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
- // 创建进程的配置对象
- mBoundApplication = data;
- mConfiguration = new Configuration(data.config);
- mCompatConfiguration = new Configuration(data.config);
- // 当版本低于 Honeycomb MR1, 将 AsyncTask 的实现通过使用线程池
- if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
- AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- // 设置应用的时区和应用的地区
- TimeZone.setDefault(null);
- LocaleList.setDefault(data.config.getLocales());
- synchronized (mResourcesManager) {
- mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
- mCurDefaultDisplayDpi = data.config.densityDpi;
- applyCompatConfiguration(mCurDefaultDisplayDpi);
- }
- // 创建 Instrumentation
- final InstrumentationInfo ii;
- if (data.instrumentationName != null) {
- try {
- ii = new ApplicationPackageManager(null, getPackageManager())
- .getInstrumentationInfo(data.instrumentationName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(
- "Unable to find instrumentation info for:" + data.instrumentationName);
- }
- mInstrumentationPackageName = ii.packageName;
- mInstrumentationAppDir = ii.sourceDir;
- mInstrumentationSplitAppDirs = ii.splitSourceDirs;
- mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
- mInstrumentedAppDir = data.info.getAppDir();
- mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
- mInstrumentedLibDir = data.info.getLibDir();
- } else {
- ii = null;
- }
- final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
- updateLocaleListFromAppContext(appContext,
- mResourcesManager.getConfiguration().getLocales());
- // Continue loading instrumentation.
- if (ii != null) {
- final ApplicationInfo instrApp = new ApplicationInfo();
- ii.copyTo(instrApp);
- instrApp.initForUser(UserHandle.myUserId());
- final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
- appContext.getClassLoader(), false, true, false);
- final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
- //
- try {
- final ClassLoader cl = instrContext.getClassLoader();
- mInstrumentation = (Instrumentation)
- cl.loadClass(data.instrumentationName.getClassName()).newInstance();
- } catch (Exception e) {
- throw new RuntimeException(
- "Unable to instantiate instrumentation"
- + data.instrumentationName + ":" + e.toString(), e);
- }
- final ComponentName component = new ComponentName(ii.packageName, ii.name);
- mInstrumentation.init(this, instrContext, appContext, component,
- data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
- if (mProfiler.profileFile != null && !ii.handleProfiling
- && mProfiler.profileFd == null) {
- mProfiler.handlingProfiling = true;
- final File file = new File(mProfiler.profileFile);
- file.getParentFile().mkdirs();
- Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
- }
- } else {
- mInstrumentation = new Instrumentation();
- }
- //Application 中指定了 big heap, 清除限制
- if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
- dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
- } else {
- dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
- }
- final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
- try {
- // 生成 Application 对象
- Application app = data.info.makeApplication(data.restrictedBackupMode, null);
- mInitialApplication = app;
- .....
- try {
- // 调用 Instrumentation 的 onCreate 方法
- mInstrumentation.onCreate(data.instrumentationArgs);
- }
- catch (Exception e) {
- }
- try {
- // 调用 Application 的 onCreate 方法
- mInstrumentation.callApplicationOnCreate(app);
- } catch (Exception e) {
- }
- } finally {
- StrictMode.setThreadPolicy(savedPolicy);
- }
- }
至此一个应用进程被打开, 同时其 Instrumentation 和 Application 的 onCreate 方法也被调用了, 接下来就是 Activity 的执行
Activity 启动到显示
从上面的进程启动可以得知每一个进程对应一个 Application, 对应一个 ActivityThread, 也对应这一个 Instrumentation 对于 Activity 的启动会调用到其
handleLaunchActivity
方法
- handleLaunchActivity
- private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
- ....
- WindowManagerGlobal.initialize();
- Activity a = performLaunchActivity(r, customIntent);
- if (a != null) {
- handleResumeActivity(r.token, false, r.isForward,
- !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
- ...
- } else {
- ActivityManagerNative.getDefault()
- .finishActivity(r.token, Activity.RESULT_CANCELED, null,
- Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
- }
- }
该方法首先对 WindowManagerGlobal 做了初始化操作, 然后调用了
performLaunchActivity
方法, 返回一个 Activity 对象后, 返回对象伪非空, 则调用
handleResumeActivity
如果为空调用 ActivityManager 的 finishActivity 方法对于启动, 这里
performLaunchActivity
和
handleResumeActivity
两个方法是核心接下来将针对这两个方法来进行分析
- private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
- // 获取该 Activity 的包信息, 这里为 LoadedApk 类型
- ActivityInfo aInfo = r.activityInfo;
- if (r.packageInfo == null) {
- r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
- Context.CONTEXT_INCLUDE_CODE);
- }
- ...
- // 创建 Activity 实例
- java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
- activity = mInstrumentation.newActivity(
- cl, component.getClassName(), r.intent);
- // 获取 Application 实例
- Application app = r.packageInfo.makeApplication(false, mInstrumentation);
- // 创建窗口实例, 并调用 activity 的 attch 方法, attach 该窗口
- Window window = null;
- if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
- window = r.mPendingRemoveWindow;
- r.mPendingRemoveWindow = null;
- r.mPendingRemoveWindowManager = null;
- }
- activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,
- r.referrer, r.voiceInteractor, window);
- ....
- // 为 Activity 设置主题
- int theme = r.activityInfo.getThemeResource();
- if (theme != 0) {
- activity.setTheme(theme);
- }
- ....
- // 调用该 Activity 的 onCreate 方法
- mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
- ....
- mActivities.put(r.token, r);
- ...
- }
首先根据 Activity 的信息来获取相关的包信息, 这里调用了 getPackInfo 来获得相关的包信息得到一个 LoadedApk 类型来表示当前的 Activity 的包信息
- public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
- int flags) {
- return getPackageInfo(packageName, compatInfo, flags, UserHandle.myUserId());
- }
其中包含了 Activity 相关的信息 Application 信息, 资源目录等等在获得了 LoadedApk 实例之后, 调用其 makApplication 方法, 我们会疑问, 在启动一个 Activity 的时候, 难道每次都要创建一个 Application 对象吗? 跟进源码
- public Application makeApplication(boolean forceDefaultAppClass,
- Instrumentation instrumentation) {
- if (mApplication != null) {
- return mApplication;
- }
- ....
- // 创建 Application 实例
- java.lang.ClassLoader cl = getClassLoader();
- if (!mPackageName.equals("android")) {
- initializeJavaContextClassLoader();
- }
- ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
- app = mActivityThread.mInstrumentation.newApplication(
- cl, appClass, appContext);
- appContext.setOuterContext(app);
- mActivityThread.mAllApplications.add(app);
- mApplication = app;
- // 调用 Application 的 onCreate 方法
- instrumentation.callApplicationOnCreate(app);
- }
通过 makeApplication 的方法实现, 我们可以看到其首先判断 Application 对象是否创建, 如果没有创建, 则初始化类装载器, 然后创建 Application 对象, 创建完成, 则调用 Application 对象的 onCreate 方法这里也就是我们所熟知的在我们自定义 Application 的时候重写的 onCreate 方法将会被调用 继续回到上面代码的分析, 这里的 Activity 通过类装载器被装载出来, 然后实例化出一个对象, 然后调用了其 attach 方法, 进行了一系列信息的配置然后调用了 mInstrumentation, 调用了
callActivityOnCreate
同时也会将我们的 Activity 添加到 mActivitys 中, 这里其定义如下
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
通过这段代码可以看到, 调用了 acticity 的 attach 方法, 跟进 attach 方法
- final void attach(Context context, ....,Window window) {
- mWindow = new PhoneWindow(this, window);
- mWindow.setWindowControllerCallback(this);
- mWindow.setCallback(this);
- mWindow.setOnWindowDismissedCallback(this);
- .....
- mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
- .....);
- .....
- mWindowManager = mWindow.getWindowManager();
- }
至此, 我们 Activity 中的 Window 已经被创建出来了 Window 实际类型为 PhoneWindow 同时为该 Window 设置了 WindowManager 至此, 我们虽然不了解 Window 是个什么东西, 但是至少, 我们可以知道的一点就是每一个 Activity 的创建是会有持有一个 Window 对象的然后 Instrumentation 的
callActivityOnCreate
方法被调用
- callActivityOnCreate
- public void callActivityOnCreate(Activity activity, Bundle icicle) {
- prePerformCreate(activity);
- activity.performCreate(icicle);
- postPerformCreate(activity);
- }
这里对于 Activity 的具体启动细节, 我们不做关心, 具体细节, 接下来的源码分析会做介绍, 这里先看一下 Activity 的 performCreate 方法
- final void performCreate(Bundle icicle) {
- restoreHasCurrentPermissionRequest(icicle);
- onCreate(icicle);
- mActivityTransitionState.readState(icicle);
- performCreateCommon();
- }
这个时候调用了 Activity 的 performCreate 函数, 调用了 Activity 的 onCreate, 我们一般会在 onCreate 中调用 setContentView, 进行我们布局文件的设置这也是比较奇怪的一点, 为什么, 我们调用了该方法, 传递一个 xml 布局文件, 我们的 View 就显示出来了呢? 这便是这次代码分析的核心, 所有围绕的相关知识点也会在此被引出接下来, 让我们剥茧抽丝, 逐层递进
- public void setContentView(@LayoutRes int layoutResID) {
- getWindow().setContentView(layoutResID);
- initWindowDecorActionBar();
- }
此处的 Window 即为在 attach 中得到的 PhoneWindow 的实例
- public void setContentView(int layoutResID) {
- if (mContentParent == null) {
- installDecor();
- } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
- mContentParent.removeAllViews();
- }
- if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
- final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
- getContext());
- transitionTo(newScene);
- } else {
- mLayoutInflater.inflate(layoutResID, mContentParent);
- }
- ...
- }
首先判断 mContentParent 是否为空, mContentParent 是用来放置 contentView 的, 如果不为空则要清理掉所有的 view, 如果为 null, 调用 installDecor(), 其中, 我们可以看到有调用对于 transitions 这个 feature 的判断, 这个是在 Android 系统 5.0 之后添加的一个功能, 可以用来实现 Activity 的过渡, 同时还是实现 Activity 之间的元素共享, 使得 Activity 间切换更加的丝滑流畅这里对于该场景不做分析, 我们跳过看其具体的 View 装载, 然后调用了
- mLayoutInflater.inflate(layoutResID, mContentParent);
- private void installDecor() {
- mDecor = generateDecor(-1);
- ....
- mContentParent = generateLayout(mDecor);
- ...
- // 过渡动画, 标题, logo,UI 选项的显示处理
- }
在 installDecor 中, 首先调用了 generateDecor 方法, 然后根据创建的 DecorView, 来生成 ContentView
- protected DecorView generateDecor(int featureId) {
- Context context;
- if (mUseDecorContext) {
- Context applicationContext = getContext().getApplicationContext();
- if (applicationContext == null) {
- context = getContext();
- } else {
- context = new DecorContext(applicationContext, getContext().getResources());
- if (mTheme != -1) {
- context.setTheme(mTheme);
- }
- }
- } else {
- context = getContext();
- }
- return new DecorView(context, featureId, this, getAttributes());
- }
根据是否使用 DecorContext 来创建相应的 context, 然后利用该 Context 来创建 DecorView 那么这个 DecorView 到底是个什么呢?
public class DecorView extends FrameLayout
DecorView 其实就是一个 FrameLayout 这个 FrameLayout 则是我们所看到的 Activity 试图的根 View, 在创建了一个 DecorView 之后, 又根据这个 DecorView 实例来创建了 ContentView
这里创建的 DecorView 其实是一个 FrameLayout,
由上面函数可以看出, mContentParent 是和 mDecor 有关的, 下面来看一下 ContentParent 的创建过程
- protected ViewGroup generateLayout(DecorView decor) {
- ...
- // 根据样式, 选择相应的资源文件, 进行相应的资源装载
- mDecor.startChanging();
- mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
- ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
- ...
- return contentParent;
- }
开始之前调用了 DecorView 的 onResourcesLoaded, 然后通过 findViewById 的方式, 返回一个 VieGroup 作为 contentParent 这里的 findViewById 的实现在基类 Window 中
- public View findViewById(@IdRes int id) {
- return getDecorView().findViewById(id);
- }
onResourcesLoaded 的方法如下
- void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
- ....
- mDecorCaptionView = createDecorCaptionView(inflater);
- final View root = inflater.inflate(layoutResource, null);
- if (mDecorCaptionView != null) {
- if (mDecorCaptionView.getParent() == null) {
- addView(mDecorCaptionView,
- new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- }
- mDecorCaptionView.addView(root,
- new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
- } else {
- addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- }
- mContentRoot = (ViewGroup) root;
- initializeElevation();
- }
根据相应的 UI 样式配置, 选择合适的布局资源文件, 然后通过 inflate 装载相应的资源文件, 创建 ContentView, 同时将其添加到 DecorView 中 在创建了 DecorView 和 ContentParent 之后, 接下来, 则利用了我们传递的 xml 布局文件 id
mLayoutInflater.inflate(layoutResID, mContentParent);
LayoutInflater 中 inflate 的实现如下
- public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
- return inflate(resource, root, root != null);
- }
- public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
- final Resources res = getContext().getResources();
- final XmlResourceParser parser = res.getLayout(resource);
- try {
- return inflate(parser, root, attachToRoot);
- } finally {
- parser.close();
- }
- }
- public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
- ....
- final View temp = createViewFromTag(root, name, inflaterContext, attrs);
- ....
- if (root != null && attachToRoot) {
- root.addView(temp, params);
- }
- ...
- }
根据我们的布局文件 ID, 创建出一个 View, 然后将该 View 添加到我们的 contentView 之中在 setContentView 中, 当我们结束了 instalDecor 方法之后, 会调用
initWindowDecorActionBar
来进行 ActionBar 的初始化操作, 创建 ActionBar
- private void initWindowDecorActionBar() {
- Window window = getWindow();
- window.getDecorView();
- if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) {
- return;
- }
- mActionBar = new WindowDecorActionBar(this);
- mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
- mWindow.setDefaultIcon(mActivityInfo.getIconResource());
- mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
- }
- handleResumeActivity
通过
performLaunchActivity
, 我们已经装载出了资源, 同时创建了 DecorView 和 contentParentView, 同时也完成了 Window 的创建, 同时也将我们设置的资源文件, 装载出来成为了 View 但是我们知道一个 Activity 可见时, 我们的 onResume 方法是被调用的了, 在 performLaunchActivity 被调用之后又调用了
- handleResumeActivity()
- final void handleResumeActivity(IBinder token,
- boolean clearHide, ....) {
- ActivityClientRecord r = mActivities.get(token);
- ...
- r = performResumeActivity(token, clearHide, reason);
- if (r.window == null && !a.mFinished && willBeVisible) {
- r.window = r.activity.getWindow();
- View decor = r.window.getDecorView();
- decor.setVisibility(View.INVISIBLE);
- ViewManager wm = a.getWindowManager();
- WindowManager.LayoutParams l = r.window.getAttributes();
- a.mDecor = decor;
- l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
- l.softInputMode |= forwardBit;
- if (r.mPreserveWindow) {
- a.mWindowAdded = true;
- r.mPreserveWindow = false;
- ViewRootImpl impl = decor.getViewRootImpl();
- if (impl != null) {
- impl.notifyChildRebuilt();
- }
- }
- if (a.mVisibleFromClient && !a.mWindowAdded) {
- a.mWindowAdded = true;
- wm.addView(decor, l);
- }
- }
该方法首先调用了
performResumeActivity
函数 performResumeActivity 中进行了大量的状态相关的判断, 而对于首次启动的分析, 我们所关心的核心就是其调用了 Activity 的 performResume, 也就是 Activity 的 onResume 函数被调用了
- public final ActivityClientRecord performResumeActivity(IBinder token,boolean clearHide, String reason) {
- ...
- r.activity.performResume();
- ...
- }
最开始调用了 Activity 的 Resume 函数, 然后进行了后续的调用这里看到一个 ViewRootImpl 中, 通过 decor 调用 getViewRootImpl() 来获得
- public ViewRootImpl getViewRootImpl() {
- if (mAttachInfo != null) {
- return mAttachInfo.mViewRootImpl;
- }
- return null;
- }
该方法中核心代码为
wm.addView(decor, l);
调用了 WindowManager 的 addView 方法, 来添加当前的 DecorView
- @Override
- public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
- applyDefaultToken(params);
- mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
- }
- public void addView(View view, ViewGroup.LayoutParams params,
- Display display, Window parentWindow) {
- ....
- ViewRootImpl root;
- View panelParentView = null;
- ....
- root = new ViewRootImpl(view.getContext(), display);
- view.setLayoutParams(wparams);
- ....
- mViews.add(view);
- mRoots.add(root);
- mParams.add(wparams);
- ....
- // do this last because it fires off messages to start doing things
- root.setView(view, wparams, panelParentView);
- }
在 WindowManager 中的 addView 调用了 WindowManagerGlobal 的 addView 方法, 在最开始的时候, 我们调用过
WindowManagerGlobal.initialize();
WindowManagerGlobal 是个单例类, 其保证了对于整个应用层, 只具备一个 WindowManagerService 同时其具备三个 ArryList, 分别保存一个应用的根 View,ViewRootImpl 和 LayoutParams, 该方法, 创建了一个 ViewRootImpl 实例, 然后将 View,ViewRoot,LayoutParams 添加到相应的 ArrayList 中, 最后调用 ViewRoot 的 setView 方法这里的 setView 方法会将其设置为自身的 View, 以后的绘制等事件都交给 ViewRootImpl 来实现绘制涉及到布局, 测量, 绘制三个环节, 具体的过程此处不再展开, 本篇主要目的是为了接下来的插件化和热修复做一个基础
总结
至此, 我们已经知道了从一个 Activity 的启动到我们的 View 逐步被创建的过程, 但是这里并没有涉及到绘制相关的内容, 那么这个 View 最终如何绘制出来的呢? 接下来, 我们首先从 ViewRootImpl 来切入做分析, 逐步理清楚接下来做的事情
来源: https://juejin.im/post/5ab9aafef265da23a141ea09