Android-App启动流程


一、Application和Activity创建

ActivityThread :其中的main方法 就是程序的入口,本质是一个handler,继承ClientTransactionHandler,ClientTransactionHandler里面有各种application和Activity的相关加载抽象类
Instrumentation:用来跟踪Application和Activity生命周期的类 ,生命周期的启动需要经过 Instrumentation

1.Application

先创建Application
–》通过调用AMS的代理类,将要创建Application的一些信息从AMS里面封装好,然后通过回调 ApplicationThread的方法将封装好的信息回调给ActivityThread,ActivityThread根据这些信将Application通过mInstrumentation用类加载机制然后反射实例化。
–》然后通过mInstrumentation调用Application的onCreate()方法

具体流程:通过ActivityThread的main方法,创建ActivityThread实力类

ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);

调用 attach去获取IActivityManager,IActivityManager本质就是ActivityManagerService

final IActivityManager mgr = ActivityManager.getService();
try {
        //让AMS持有ApplicationThread,这样方便AMS和ActivityThread相互调用
    mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
    throw ex.rethrowFromSystemServer();
}

所以attachApplication其实就是ActivityManagerService的方法,他主要是初始化一些Application和Activity的数据,为他们的创建做准备

public final void attachApplication(IApplicationThread thread, long startSeq) {
    if (thread == null) {
        throw new SecurityException("Invalid application interface");
    }
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
                //从AMS中获取创建application所需要的一些数据
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}

获取到数据之后回调给ActivityThtead

@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
//获取到数据之后回调给ActivityThtead
thread.bindApplication(processName, appInfo, providerList,
        instr2.mClass,
        profilerInfo, instr2.mArguments,
        instr2.mWatcher,
        instr2.mUiAutomationConnection, testMode,
        mBinderTransactionTrackingEnabled, enableTrackAllocation,
        isRestrictedBackupMode || !normalMode, app.isPersistent(),
        new Configuration(app.getWindowProcessController().getConfiguration()),
        app.compat, getCommonServicesLocked(app.isolated),
        mCoreSettingsObserver.getCoreSettingsLocked(),
        buildSerial, autofillOptions, contentCaptureOptions,
        app.mDisabledCompatChanges);
}

然后回调到ActivityThread的bindApplication方法,这个方法主要是将从AMS获取到的一些数据进行封装

@Override
public final void bindApplication(String processName, ApplicationInfo appInfo,
        ProviderInfoList providerList, ComponentName instrumentationName,
        ProfilerInfo profilerInfo, Bundle instrumentationArgs,
        IInstrumentationWatcher instrumentationWatcher,
        IUiAutomationConnection instrumentationUiConnection, int debugMode,
        boolean enableBinderTracking, boolean trackAllocation,
        boolean isRestrictedBackupMode, boolean persistent, Configuration config,
        CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
        String buildSerial, AutofillOptions autofillOptions,
        ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
    if (services != null) {
        if (false) {
            // Test code to make sure the app could see the passed-in services.
            for (Object oname : services.keySet()) {
                if (services.get(oname) == null) {
                    continue; // AM just passed in a null service.
                }
                String name = (String) oname;


                // See b/79378449 about the following exemption.
                switch (name) {
                    case "package":
                    case Context.WINDOW_SERVICE:
                        continue;
                }


                if (ServiceManager.getService(name) == null) {
                    Log.wtf(TAG, "Service " + name + " should be accessible by this app");
                }
            }
        }


        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }


    setCoreSettings(coreSettings);


    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providerList.getList();
    data.instrumentationName = instrumentationName;
    data.instrumentationArgs = instrumentationArgs;
    data.instrumentationWatcher = instrumentationWatcher;
    data.instrumentationUiAutomationConnection = instrumentationUiConnection;
    data.debugMode = debugMode;
    data.enableBinderTracking = enableBinderTracking;
    data.trackAllocation = trackAllocation;
    data.restrictedBackupMode = isRestrictedBackupMode;
    data.persistent = persistent;
    data.config = config;
    data.compatInfo = compatInfo;
    data.initProfilerInfo = profilerInfo;
    data.buildSerial = buildSerial;
    data.autofillOptions = autofillOptions;
    data.contentCaptureOptions = contentCaptureOptions;
    data.disabledCompatChanges = disabledCompatChanges;
    sendMessage(H.BIND_APPLICATION, data);
}

最后通过sendMessage(H.BIND_APPLICATION, data);Handler开始分发创建Application的消息

case BIND_APPLICATION:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
    AppBindData data = (AppBindData)msg.obj;
    handleBindApplication(data);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;

将Application通过mInstrumentation用类加载机制然后反射实例化。然后,通过mInstrumentation启动 Application的onCreate方法,加载Applicatin

@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
...

try {
        //反射获取mInstrumentation
        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();
    mInstrumentation.basicInit(this);
}
try {
    mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
    throw new RuntimeException(
        "Exception thrown in onCreate() of "
        + data.instrumentationName + ": " + e.toString(), e);
}
try {
    mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
    if (!mInstrumentation.onException(app, e)) {
        throw new RuntimeException(
          "Unable to create application " + app.getClass().getName()
          + ": " + e.toString(), e);
    }
}
...
}

2.Activity

创建Activity
–》同上,通过AMS代理类,封装要创建的Activity的信息,然后回调给ActivityThread,通过mInstrumentation创建Activity并且调用它的onCreate()方法,具体查看下面流程图
在这里插入图片描述

二、UI绘制流程

DecorView 是窗口的顶层试图,包含所以的窗口装饰

1.继承Activity加载xml文件

点击setContentView -->会走PhoneWindow的setContentView方法–>在setContentView中的installDecor会去初始化DecorView和ViewGroup -->在ViewGroup的layoutResource会去加载默认的布局样式–>然后调用mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);把基础布局添加到DecorView中,–>返回到setContentView方法,然后就开始解析xml文件–>解析后,通过root.addView(temp, params);把我们自定义的布局添加到ViewGroup中 -->回调到ActivityThread的handleResumeActivity方法,然后通过以下几个方法去绘制view,View decor = r.window.getDecorView();ViewManager wm = a.getWindowManager(); wm.addView(decor, l);

2.继承AppCompatActivity加载xml文件

点击setContentView --> 走到AppCompatDelegateImpl的setContentView方法—>调用ensureSubDecor,在里面调用createSubDecorf方法创建ViewGroup的对象mSubDecor–》createSubDecorf方法中做了一些初始化的操作,根据对应主题初始化subDecor,然后修改原有布局id,替换成content布局—》最后给phoneWindow设置布局mWindow.setContentView(subDecor);—》在回到AppCompatDelegateImpl的setContentView方法,点击inflate方法—》最后调用return inflate(parser, root, attachToRoot);–》最后root.addView(temp, params);会把把我们自定义的布局添加到ViewGroup中–>回调到ActivityThread的handleResumeActivity方法,然后通过以下几个方法去绘制view,View decor = r.window.getDecorView();ViewManager wm = a.getWindowManager(); wm.addView(decor, l);
替换布局的代码:

final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
        R.id.action_bar_activity_content);


final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
if (windowContentView != null) {
    // There might be Views already added to the Window's content view so we need to
    // migrate them to our content view
    while (windowContentView.getChildCount() > 0) {
        final View child = windowContentView.getChildAt(0);
        windowContentView.removeViewAt(0);
        contentView.addView(child);
    }


    // Change our content FrameLayout to use the android.R.id.content id.
    // Useful for fragments.
    windowContentView.setId(View.NO_ID);
    contentView.setId(android.R.id.content);


    // The decorContent may have a foreground drawable set (windowContentOverlay).
    // Remove this as we handle it ourselves
    if (windowContentView instanceof FrameLayout) {
        ((FrameLayout) windowContentView).setForeground(null);
    }
}
mWindow.setContentView(subDecor);

最简单的描述就是:
–》先加载基础布局,然后加载自己定义的布局
ActivityThread里面的handleResumeActivity来调用Activity的根布局的测量布局绘制
因为根布局是一个ViewGroup,会把测量布局绘制传递给子View,最终都会执行对应的方法
加载流程图:
在这里插入图片描述

三、View的绘制流程

在ActivityThread的handleResumeActivity,这是activity解析完xml回调回来的方法,这里获取到ViewManager并且把view添加进来

 @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
    ...
     View decor = r.window.getDecorView();
     final Activity a = r.activity;
     ViewManager wm = a.getWindowManager();
    ...
    wm.addView(decor, l);
    ...
}

然后回调到WindowManagerImpl的addView方法

@Override 
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
            mContext.getUserId());
}

然后找到,点击跳转到 ViewRootImpl类中

root.setView(view, wparams, panelParentView, userId);

ViewRootImpl类中的setView方法做了View的绘制的一系列流程

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
        ...
        requestLayout();
        }
    }
}

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

@UnsupportedAppUsage
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
                //织物着启动调度线程
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        //执行调度
        doTraversal();
    }
}

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);


        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }


        performTraversals();


        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}
//View 绘制
private void performTraversals() {
    ...
    //测量View的宽高
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    ...
    //计算当前View以及子View的位置
    performLayout(lp, mWidth, mHeight);
    ...
        //开始调用绘制流程
    performDraw();
    ...    
}

这就是为啥自定义View的时候,先onMeasure和onlayout,最后ondraw

下面是流程图:
在这里插入图片描述


总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值