Android进程启动与Activity显示

作者: Jensen95 | 来源:发表于2018-03-27 11:00 被阅读293次

    前言

    这段时间,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函数。

    image.png
    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的执行。

    ActivityThread mian函数执行

    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方法。对于启动,这里performLaunchActivityhandleResumeActivity两个方法是核心。接下来将针对这两个方法来进行分析。

    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来实现。绘制涉及到布局,测量,绘制三个环节,具体的过程此处不再展开,本篇主要目的是为了接下来的插件化和热修复做一个基础。

    总结

    View创建流程

    至此,我们已经知道了从一个Activity的启动到我们的View逐步被创建的过程,但是这里并没有涉及到绘制相关的内容,那么这个View最终如何绘制出来的呢?接下来,我们首先从ViewRootImpl来切入做分析,逐步理清楚接下来做的事情。

    相关文章

      网友评论

        本文标题:Android进程启动与Activity显示

        本文链接:https://www.haomeiwen.com/subject/nvpjcftx.html