Android应用程序启动详解(二)从源码了解App的启动过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lyz_zyx/article/details/82917123

本文承接《Android应用程序启动详解(一)》继续来学习应用程序的启动的那些事。上文提到startActivity()方法启动一个app后经过一翻过程就到了app的入口方法ActivityThread.main()。其实我们在之前的文章中《Android的消息机制(二)之Looper的使用》介绍主线程为何可接收消息时也简单提到过此入口方法。关于主线程可接收消息的原因是因为在ActivityThread.main()中为主线程创建了Looper。现在我们继续来再看看ActivityThread.main()方法的源码:

Application的启动过程

ActivityThread.java

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    SamplingProfilerIntegration.start();

    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    // Set the reporter for event logging in libcore
    EventLogger.setReporter(new EventLoggingReporter());

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    // 创建Looper
    Looper.prepareMainLooper();

    // 关键代码:ActivityThread初始化,并调用attach()方法
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    // 开启消息循环
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

可以看到,main()方法是一个静态方法,ActivityThread对象在方法里做了初始化,并调用了attach方法。我们继续看下attach方法的源码:

final ApplicationThread mAppThread = new ApplicationThread();
……
private void attach(boolean system) {

    sCurrentActivityThread = this;

    mSystemThread = system;
    // 非系统app
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                ensureJitEnabled();
            }
        });

        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());

        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        // 关键代码1:获得一个IActivityManager对象
        final IActivityManager mgr = ActivityManagerNative.getDefault();

        try {
            // 关键代码2:调用IActivityManager对象的attachApplication方法
            mgr.attachApplication(mAppThread);

        } catch (RemoteException ex) {

            throw ex.rethrowFromSystemServer();

        }
        ……
    } else {
        // 系统app……
    }
    ……
}

attach方法接收一个参数:system,用于区分是否系统app,这里我们传入的是false,所以我们只看非系统app的判断分支代码,这里有两行关键代码:

逻辑意思是通过ActivityManagerNative的getDefault()方法获得一个IActivityManager对象,在前面《Android应用程序启动详解(一)》我们已经了解到此对象就是ActivityManagerService。所以代码:mgr.attachApplication(mAppThread);中attachApplication方法实体便在ActivityManagerService中,参数是ApplicationThread对象,看代码:

ActivityManagerService.java

@Override
public final void attachApplication(IApplicationThread thread) {

    synchronized (this) {

        int callingPid = Binder.getCallingPid();

        final long origId = Binder.clearCallingIdentity();
        // 关键代码
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {

        ……
        ProfilerInfo profilerInfo = profileFile == null ? null : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
        // 关键代码1
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,

                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked());
        updateLruProcessLocked(app, false, null);
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
    } catch (Exception e) {
        ……
    }
     ……
       if (normalMode) {
        try {
            // 关键代码2 去启动Activity
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    ……
    return true;
}

attachApplication方法中调用了另外一个关键的方法:attachApplicationLocked。attachApplicationLocked方法细节够多,我们只看关键部分,请先记住关键代码2,这是Application启动成功后,Activity的启动关键过程,我们后面来分析,现在请看关键代码1这行,我们前面知道,thread是ActivityThread中的ApplicationThread对象,这里thread也是继承了IBinder,这里也进行了跨进程进程间通信,所以又回到ActivityThread中查看代码:

ActivityThread.java

public final void bindApplication(String processName, ApplicationInfo appInfo,
        List<ProviderInfo> providers, 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<String, IBinder> services, Bundle coreSettings) {

    if (services != null) {
        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);

    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
    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;
    sendMessage(H.BIND_APPLICATION, data);
}

此处看得到,是发了一个BIND_APPLICATION消息,继续看看消息接收地方做了啥事情:

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        ……
        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;
            }
            ……
    Object obj = msg.obj;
    if (obj instanceof SomeArgs) {
        ((SomeArgs) obj).recycle();
    }
    if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}

这里关键代码是handleBindApplication方法,继续向下看源码:

private void handleBindApplication(AppBindData data) {
    ……
    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
    try {
        // 关键代码1
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;

        if (!data.restrictedBackupMode) {
            if (!ArrayUtils.isEmpty(data.providers)) {
                installContentProviders(app, data.providers);
                mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
            }
        }

        try {
            mInstrumentation.onCreate(data.instrumentationArgs);

        }
        catch (Exception e) {
            throw new RuntimeException( "Exception thrown in onCreate() of "
                + data.instrumentationName + ": " + e.toString(), e);
        }

        try {
            // 关键代码2
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    } finally {
        StrictMode.setThreadPolicy(savedPolicy);
    }
}

这也是一个够长的方法,我们还是只看关键代码行:关键代码1中data.info是一个LoadedApk类对象,它返回一了一个Application对象,并赋予全局变量mInitialApplication。到此你一定猜测些Application对象是不是就是我们app中常用的Application对象?答案是:你猜对了。再来看关键代码2,在创建出Application对象后,调用了callApplicationOnCreate(app)方法:

Instrumentation.java

public void callApplicationOnCreate(Application app) {
    app.onCreate();
}

这就是我们继承Application类的onCreate()方法了。看到这里应该会有点小兴奋吧,因为我们终于知道了Application的onCreate()方法被回调的原理了。事情还没完,让我们继续刨根问底,看看Application是如何创建出来的,看回handleBindApplication()方法的关键代码1调用的makeApplication()方法,它的源码:

LoadedApk.java

public Application makeApplication(boolean forceDefaultAppClass,

        Instrumentation instrumentation) {

    if (mApplication != null) {
        return mApplication;
    }

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
    Application app = null;
    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "initializeJavaContextClassLoader");
            initializeJavaContextClassLoader();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // 关键代码
        app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }

    mActivityThread.mAllApplications.add(app);
    mApplication = app;
    ……
    return app;
}

请看关键代码行,方法参数传入了继承Application的类的类名appClass,再看源码:

public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return newApplication(cl.loadClass(className), context);

}

static public Application newApplication(Class<?> clazz, Context context)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {

    Application app = (Application)clazz.newInstance();
    app.attach(context);
    return app;
}

上面代码很简单了,在创建Application后,就调用了attach方法:

Application.java

final void attach(Context context) {
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

ContextWrapper.java

protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}

能看出,在Application创建后,第一个调用的是attachBaseContext()方法,然后再是onCreate()方法。

Activity的启动过程

回到上面提到的ActivityManagerService.java中的attachApplicationLocked()方法关键代码2处(红色醒目文字提到先记住后面分析处),Application启动成功后,下一步就是要启动Activity了,请再看attachApplicationLocked()方法:

ActivityManagerService.java

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
        ……
        ProfilerInfo profilerInfo = profileFile == null ? null : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
        // 关键代码1
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked());
        updateLruProcessLocked(app, false, null);
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
    } catch (Exception e) {
        ……
    }
     ……
       if (normalMode) {
        try {
            // 关键代码2 去启动Activity
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    ……
    return true;
}

这次我们来看关键代码2,mStackSupervisor变量是一个ActivityStackSupervisor类型,这个类也是非常重要的,它决定着我们app是否能启动成功,我们看看做了什么:

ActivityStackSupervisor.java

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {

    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {

               // 关键代码1:当前应用的整个activity堆栈信息
               ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (!isFrontStack(stack)) {
                continue;
            }
            ActivityRecord hr = stack.topRunningActivityLocked(null);
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        // 关键代码2:启动Activity
                        if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                              + hr.intent.getComponent().flattenToShortString(), e);
                        throw e;
                    }
                }
            }
        }
    }
    if (!didSomething) {
        ensureActivitiesVisibleLocked(null, 0);
    }
    return didSomething;
}

关键代码1处就是获得Activity的堆栈信息,我们继续看关键代码2 调用了realStartActivityLocked()方法,这方法也是之前《Android应用程序启动详解(一)》中“从startActivity()到ActivityThread.main()流程源码分析”提到要先记住,这是也是从应用中启动Activity所调用的方法,请看源码:

final boolean realStartActivityLocked(ActivityRecord r,
        ProcessRecord app, boolean andResume, boolean checkConfig)
        throws RemoteException {
        ……
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
        // 关键代码
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
                r.icicle, r.persistentState, results, newIntents, !andResume,
                mService.isNextTransitionForward(), profilerInfo);
        ……
    return true;
}

请看关键代码,其中app是上一层传过来的ActivityRecord,它代表的就是要开启的Activity对象里面分装了很多信息,比如所在的ActivityTask等,如果这是首次打开应用,那么这个Activity会被放到ActivityTask的栈顶,那么app.thread这个IApplicationThread对象,这个就是我们的ApplicationThread,所以scheduleLaunchActivity()方法是:

ActivityThread.java

private class ApplicationThread extends ApplicationThreadNative {

    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
            String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
            PersistableBundle persistentState, List<ResultInfo> pendingResults,
            List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
            ProfilerInfo profilerInfo) {

        updateProcessState(procState, false);
        ActivityClientRecord r = new ActivityClientRecord();
        r.token = token;
        r.ident = ident;
        r.intent = intent;
        r.referrer = referrer;
        r.voiceInteractor = voiceInteractor;
        r.activityInfo = info;
        r.compatInfo = compatInfo;
        r.state = state;
        r.persistentState = persistentState;
        r.pendingResults = pendingResults;
        r.pendingIntents = pendingNewIntents;
        r.startsNotResumed = notResumed;
        r.isForward = isForward;
        r.profilerInfo = profilerInfo;
        updatePendingConfiguration(curConfig);
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }
}

老套路和Application相似,通过发送消息,这里发了一个LAUNCH_ACTIVITY消息,继续看看消息接收地方做了啥事情:

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
            r.packageInfo = getPackageInfoNoCheck(
                    r.activityInfo.applicationInfo, r.compatInfo);
            // 关键代码
            handleLaunchActivity(r, null);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;
        ……
    }
    if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ……
    // 关键代码
    Activity a = performLaunchActivity(r, customIntent);
    ……
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent){
    ……
    Activity activity = null;
    try {
        // 关键代码1:通过类加载器创建activity实例
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        ……
        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            // 关键代码2:对Activity进行了初始化
            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);
            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
                activity.setTheme(theme);
            }
            activity.mCalled = false;
            // 关键代码3:activity的onCreate的回调
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            ……
    } catch (SuperNotCalledException e) {
        throw e;
    } catch (Exception e) {
        ……
    }
    return activity;
}

请看关键代码1,内部是通过类加载器创建activity实例:

public Activity newActivity(ClassLoader cl, String className,
        Intent intent)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

请看关键代码2,内部主要是对Activity进行了初始化了一些重要的数据,如Window的创建和关联就是这此处完成:

Activity.java

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
    attachBaseContext(context);

    mFragments.attachActivity(this, mContainer, null);
    mWindow = PolicyManager.makeNewWindow(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    mUiThread = Thread.currentThread();

    mMainThread = aThread;
    mInstrumentation = instr;
    mToken = token;
    mIdent = ident;
    mApplication = application;
    mIntent = intent;
    mReferrer = referrer;
    mComponent = intent.getComponent();
    mActivityInfo = info;
    mTitle = title;
    mParent = parent;
    mEmbeddedID = id;
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    if (voiceInteractor != null) {
        if (lastNonConfigurationInstances != null) {
            mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
        } else {
            mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                    Looper.myLooper());
        }
    }

    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;
}

再来看关键代码3,这套路跟Application也是很相似的,它是activity的onCreate的回调的处理:

Instrumentation.java

public void callActivityOnCreate(Activity activity, Bundle icicle,
        PersistableBundle persistentState) {
    prePerformCreate(activity);
    // 关键代码
    activity.performCreate(icicle, persistentState);
    postPerformCreate(activity);
}

Activity.java

final void performCreate(Bundle icicle, PersistableBundle persistentState) {
    onCreate(icicle, persistentState);
    mActivityTransitionState.readState(icicle);
    performCreateCommon();
}

可以看到,最后的确是调用了Activity的OnCreate方法。就这样,Activity的启动流程就介绍完了。

总结

还是那句,看源码真的会让人感到乏味和无趣,整个过程真的是又长又臭,但主要记住关键点其实就足够了:

  1. Android中app在Application创建后,第一个调用的是attachBaseContext()方法,然后再是onCreate()方法。
  2. Android中app在Activity创建后,第一个调用的是onCreate()方法

猜你喜欢

转载自blog.csdn.net/lyz_zyx/article/details/82917123