Android进阶笔记-7. Context详解

Context数量

  • Activity数量 + Service数量 + 1 (1为Application)

Context的继承关系

  • Context下有两个子类,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类;
  • ContextWrapper作为Context类的包装类,其内部维护了一个Context类型的成员变量mBase,mBase最终会指向一个ContextImpl对象,ContextWrapper的方法其内部依赖mBase,ContextWrapper是Context类的修饰类(装饰器模式),真正的实现类是 ContextImpl,ContextWrapper 里面的方法调用也是调用 ContextImpl 里面的方法。又有三个直接的子类,ContextThemeWrapper, Service, Application; ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity;
  • ContextImpl中两个比较重要的变量:
    • ActivityThread mMainThread:getApplicationContext,startActivity,getMainLooper
    • LoadedApk mPackageInfo: getApplicationContext, getPackageName, getApplicationInfo, getPackageResourcePath

Application Context 创建过程

  • 当一个应用程序启动完成后,应用程序就会有一个全局的Application Context
  • ActivityThread作为应用程序进程的核心类,它会调用它的内部类ApplicationThread的scheduleLaunchActivity方法来启动Activity,scheduleLaunchActivity方法中向H类发送LAUNCH_ACTIVITY类型的消息,目的是将启动Activity的逻辑放在主线程中的消息队列中,这样启动Activity的逻辑会在主线程中执行。
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
        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;

    r.overrideConfig = overrideConfig;
    updatePendingConfiguration(curConfig);

    sendMessage(H.LAUNCH_ACTIVITY, r);
}
  • H类的handleMessage方法对LAUNCH_ACTIVITY类型的消息的处理,通过getPackageInfoNoCheck方法获得LoadedApk类型的对象,并将该对象赋值给ActivityClientRecord 的成员变量packageInfo
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;
          //1.通过getPackageInfoNoCheck方法获得LoadedApk类型的对象,并将该对象赋值给ActivityClientRecord 的成员变量packageInfo
          r.packageInfo = getPackageInfoNoCheck(
              r.activityInfo.applicationInfo, r.compatInfo);
          //2. handleLaunchActivity方法中调用了performLaunchActivity
          handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
          Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
      } break;
    ...
}
  • handleLaunchActivity方法中调用了performLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;

    if (r.profilerInfo != null) {
        mProfiler.setProfiler(r.profilerInfo);
        mProfiler.startProfiling();
    }

    // Make sure we are running with the most recent config.
    handleConfigurationChanged(null, null);

    if (localLOGV) Slog.v(
        TAG, "Handling launch of " + r);

    // Initialize before creating the activity
    WindowManagerGlobal.initialize();

    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        if (!r.activity.mFinished && r.startsNotResumed) {
            performPauseActivityIfNeeded(r, reason);
            if (r.isPreHoneycomb()) {
                r.state = oldState;
            }
        }
    } else {
        try {
            ActivityManager.getService()
                .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                        Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}


private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
       ...
    } 
    ...
    return activity;
}
  • performLaunchActivity中又调用了LoadedApk的makeApplication方法
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {//1
        return mApplication;
    }
    ...
    try {
      ...
       java.lang.ClassLoader cl = getClassLoader();
      ...
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);//2
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);//3
        appContext.setOuterContext(app);//4
    } catch (Exception e) {
       ...
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;//5
    ...
    return app;
}
  • Instrumentation的newApplication方法如下
static public Application newApplication(Class<?> clazz, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
    Application app = (Application)clazz.newInstance();//1
    app.attach(context);
    return app;
}

//frameworks/base/core/java/android/app/Application.java
/* package */ final void attach(Context context) {
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

//frameworks/base/core/java/android/content/ContextWrapper.java
protected void attachBaseContext(Context base) {
     if (mBase != null) {
         throw new IllegalStateException("Base context already set");
     }
     mBase = base;
}

Application Context 获取过程

  • 调用getApplicationContext方法来获得Application Context,实现在ContextWrapper中
@Override
public Context getApplicationContext() {
    return mBase.getApplicationContext();
}
  • mBase指的是ContextImpl,我们来查看 ContextImpl的getApplicationContext
@Override
public Context getApplicationContext() {
    return (mPackageInfo != null) ?
            mPackageInfo.getApplication() : mMainThread.getApplication();
}
  • 由于应用程序这时已经启动,因此LoadedApk不会为null,则会调用LoadedApk的getApplication方法
Application getApplication() {
     return mApplication;//在上文LoadedApk的makeApplication方法的注释5处被赋值
}

Activity的Context创建过程

  • 前面 Application Context 创建过程讲到了ActivityThread启动Activity的过程,ActivityThread会调用它的内部类ApplicationThread的scheduleLaunchActivity方法来启动Activity,scheduleLaunchActivity方法中向H类发送LAUNCH_ACTIVITY类型的消息,H类的handleMessage方法对LAUNCH_ACTIVITY类型的消息的处理,调用了handleLaunchActivity方法,handleLaunchActivity方法中又调用了performLaunchActivity,performLaunchActivity中调用了LoadedApk类型的packageInfo的makeApplication方法
  • 而performLaunchActivity中还有很多重要的逻辑,如下可以看到还有调用了一个createBaseContextForActivity方法
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }
    //创建Activity的ContextImpl
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        //创建Activity的实例
        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 {
        // 前面说的调用makeApplication创建Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        if (activity != null) {
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
           
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            //调用了ContextImpl的setOuterContext方法,
            //将此前创建的Activity实例赋值给ContextImpl的成员变量mOuterContext,
            //这样ContextImpl也可以访问Activity的变量和方法
            appContext.setOuterContext(activity);
            //将ContextImpl传入activity的attach方法中
            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, r.configCallback);

            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            checkAndBlockForNetworkAccess();
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
                activity.setTheme(theme);
            }

            activity.mCalled = false;
            //Instrumentation的callActivityOnCreate方法中会调用Activity的onCreate方法
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }
            r.activity = activity;
            r.stopped = true;
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                r.persistentState);
                    }
                } else if (r.state != null) {
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,
                            r.persistentState);
                } else {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onPostCreate()");
                }
            }
        }
        r.paused = true;

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to start activity " + component
                + ": " + e.toString(), e);
        }
    }

    return activity;
}
  • createBaseContextForActivity方法
 private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    ...
    //调用ContextImpl的createActivityContext方法来创建ContextImpl
    ContextImpl appContext = ContextImpl.createActivityContext(
            this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

    ...
    return appContext;
}
  • Activity的attach方法调用了ContextThemeWrapper的attachBaseContext方法
 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,
        Window window, ActivityConfigCallback activityConfigCallback) {
        
    //调用了ContextThemeWrapper的attachBaseContext方法
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);
    //创建PhoneWindow,PhoneWindow在运行中会间接触发很多事件,
    //比如点击事件、菜单弹出、屏幕焦点变化等事件,
    //这些事件需要转发给与PhoneWindow关联的Actvity,
    //转发操作通过Window.Callback接口实现,Actvity实现了这个接口
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);//将当前Activity通过Window的setCallback方法传递给PhoneWindow
    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());
        }
    }
    //给PhoneWindow设置WindowManager
    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());
    }
    //获取WindowManager并赋值给Activity的成员变量mWindowManager,
    //这样在Activity中就可以通过getWindowManager方法来获取WindowManager
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;

    mWindow.setColorMode(info.colorMode);
}
  • 上面第一行就调用了ContextThemeWrapper的attachBaseContext方法,
    其中直接调用了其父类ContextWrapper的attachBaseContext方法
@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(newBase);
}

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

//base指的是一路传递过来的Activity的ContextImpl,
//将它赋值给ContextWrapper的成员变量mBase。
//这样ContextWrapper的功能就可以交由ContextImpl处理,例如
@Override
public Resources.Theme getTheme() {
    return mBase.getTheme();
}
//调用ContextWrapper的getTheme方法,其实就是调用的ContextImpl的getTheme方法

Service的Context创建过程

  • ActivityThread的内部类ApplicationThread会调用scheduleCreateService方法来启动Service
public final void scheduleCreateService(IBinder token,
        ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
    updateProcessState(processState, false);
    CreateServiceData s = new CreateServiceData();
    s.token = token;
    s.info = info;
    s.compatInfo = compatInfo;

    sendMessage(H.CREATE_SERVICE, s);
}
  • 可以看到上面也是通过向H类发送CREATE_SERVICE类型的消息,H类的handleMessage方法中会对CREATE_SERVICE类型的消息进行处理,其中调用了handleCreateService方法
case CREATE_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
    handleCreateService((CreateServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
    
private void handleCreateService(CreateServiceData data) {
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        //创建service
        service = (Service) cl.loadClass(data.info.name).newInstance();
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to instantiate service " + data.info.name
                + ": " + e.toString(), e);
        }
    }

    try {
        //创建ContextImpl实例
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        //调用了ContextImpl的setOuterContext方法,
        //将service实例赋值给ContextImpl的成员变量mOuterContext,
        //这样ContextImpl也可以访问service的变量和方法
        context.setOuterContext(service);
        //创建(获取)Application实例
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        //将ContextImpl实例传入service的attach方法
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        //调用service的onCreate方法
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
}
  • 上面可以看到其中创建了ContextImpl,并将该ContextImpl传入service的attach方法中
public final void attach(
        Context context,
        ActivityThread thread, String className, IBinder token,
        Application application, Object activityManager) {
        
    //调用了ContextWrapper的attachBaseContext方法
    attachBaseContext(context);
    mThread = thread;           // NOTE:  unused - remove?
    mClassName = className;
    mToken = token;
    mApplication = application;
    mActivityManager = (IActivityManager)activityManager;
    mStartCompatibility = getApplicationInfo().targetSdkVersion
            < Build.VERSION_CODES.ECLAIR;
}
  • 可以看到最终也是调用到了ContextWrapper的attachBaseContext方法

几个容易混乱方法

  • 再来看一下几个常见的获取context的方法
  • getBaseContext是ContextWrapper中的方法,其返回的mBase也就是上面提到的通过attachBaseContext赋值的ContextImpl实例
 /**
 * @return the base context as set by the constructor or setBaseContext
 */
public Context getBaseContext() {
    return mBase;
}
  • getApplicationContext是ContextWrapper中的方法,其返回是调用了ContextImpl实例mBase的getApplicationContext方法,最终返回的是一个Application实例
@Override
public Context getApplicationContext() {
    return mBase.getApplicationContext();
}

//ContextImpl的getApplicationContext方法
@Override
public Context getApplicationContext() {
    return (mPackageInfo != null) ?
            mPackageInfo.getApplication() : mMainThread.getApplication();
}
  • getApplication是Activity/service中的方法,实在上面的attach方法中赋值给mApplication的Application实例
/** Return the application that owns this activity. */
public final Application getApplication() {
    return mApplication;
}
  • getContext是Fragment中的方法,返回的是通过调用FragmentHostCallback类型的mHost的getContext方法返回其mContext变量
@Nullable
public Context getContext() {
    return mHost == null ? null : mHost.getContext();
}
  • FragmentHostCallback的getContext方法
@NonNull
Context getContext() {
    return mContext;
}

FragmentHostCallback(@NonNull FragmentActivity activity) {
    this(activity, activity /*context*/, new Handler(), 0 /*windowAnimations*/);
}

FragmentHostCallback(@Nullable Activity activity, @NonNull Context context,
        @NonNull Handler handler, int windowAnimations) {
    mActivity = activity;
    mContext = Preconditions.checkNotNull(context, "context == null");
    mHandler = Preconditions.checkNotNull(handler, "handler == null");
    mWindowAnimations = windowAnimations;
}
  • 其调用是在
public class FragmentActivity extends ComponentActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {
    ...
    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    ...
    class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements  ViewModelStoreOwner, OnBackPressedDispatcherOwner {
        public HostCallbacks() {
            super(FragmentActivity.this /*fragmentActivity*/);
        }
        ...
    }
    ...
}
  • 上面可以看到其实mContext和mActivity都是通过FragmentActivity.this赋值的
  • 打印log看一下
getBaseContext():androidx.appcompat.view.ContextThemeWrapper
getApplicationContext():android.app.Application
getApplication():android.app.Application
this:com.example.viewpagerdemo.MainActivity
Fragment getContext():com.example.viewpagerdemo.MainActivity

正确使用Context

  • 一般Context造成的内存泄漏,几乎都是当Context销毁的时候,却因为被引用导致销毁失败
  • 优先使用Application的Context,或用弱引用进行封装
  • ImageView等都会持有上下文的引用,如果设置了static Drawable对象,就会导致该内存无法释放
activity的startActivity和context的startActivity区别?
  1. 从Activity中启动新的Activity时可以直接mContext.startActivity(intent)就好,如果从其他Context中启动Activity则必须给intent设置Flag:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ;
mContext.startActivity(intent);
原理:
  1. 首先startActivity是Context中的抽象方法
public abstract void startActivity(@RequiresPermission Intent intent);
  1. ContextWrapper中是调用了mBase的,也就是ContextImpl的实现
@Override
public void startActivity(Intent intent) {
    mBase.startActivity(intent);
}
  1. ContextImpl的实现,会先检查有没有设置Flag:FLAG_ACTIVITY_NEW_TASK,再调用了mMainThread.getInstrumentation().execStartActivity方法
@Override
public void startActivity(Intent intent) {
    warnIfCallingFromSystemProcess();
    startActivity(intent, null);
}



@Override
public void startActivity(Intent intent, Bundle options) {
    warnIfCallingFromSystemProcess();

    // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
    // generally not allowed, except if the caller specifies the task id the activity should
    // be launched in.
    if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
            && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
        throw new AndroidRuntimeException(
                "Calling startActivity() from outside of an Activity "
                + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                + " Is this really what you want?");
    }
    mMainThread.getInstrumentation().execStartActivity(
            getOuterContext(), mMainThread.getApplicationThread(), null,
            (Activity) null, intent, -1, options);
}
  1. ContextThemeWrapper中没有实现此方法
  2. Activity中重写了startActivity方法,最终调用了mInstrumentation.execStartActivity方法,跳过了检查FLAG_ACTIVITY_NEW_TASK
@Override
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}
  • 当调用startActivity()方法来启动一个Activity时,默认是将它放入到当前的任务当中。但是,如果在Intent中加入了FLAG_ACTIVITY_NEW_TASK flag的话,情况就会变的复杂起来。首先,系统会去检查这个Activity的affinity是否与当前Task的affinity相同。如果相同的话就会把它放入到当前Task当中,如果不同则会先去检查是否已经有一个名字与该Activity的affinity相同的Task,如果有,这个Task将被调到前台,同时这个Activity将显示在这个Task的顶端;如果没有的话,系统将会尝试为这个Activity创建一个新的Task。需要注意的是,如果一个Activity在manifest文件中声明的启动模式是”singleTask”,那么他被启动的时候,行为模式会和前面提到的指定FLAG_ACTIVITY_NEW_TASK一样。
  • 几种启动模式
类型含义说明
standard标准模式每启动会创建一个新 Activity 实例并置于栈顶。谁启动了这个 Activity,那么这个 Activity 就运行在启动它的那个 Activity 所在的栈中。
singleTop栈顶模式如果栈顶存在该activity的实例,则复用,不存在新建放入栈顶,例如通知栏点击后需要启动一个活动页
singleTask栈内复用模式如果栈内存在该 Activity 的实例则进行复用(会将该实例上边的 Activity 全部出栈,将该实例置于栈顶),如果不存在则创建。例如主 Activity 的启动模式改为栈内复用,再跳转到另一个二级页,按home键回到桌面,再切回,二级页会被销毁。
singleInstance单实例模式这种模式启动的activity只能单独的位于一个任务栈中,在整个应用中仅存在单个实例,APP首页/主页/呼叫来电界面
singleInstancePerTask栈内根单例每个任务里存在于根部的单个实例,多窗口并排功能的时候可以使用,例如:Chrome 浏览器的多窗口
  • 启动模式优先级: Intent标记 > AndroidManifest文件
Android12 中 Activity 生命周期的变化
  • Android 12 以前,当我们处于 Root Activity 时,点击返回键时,应用返回桌面, Activity 执行 onDestroy,程序结束。 Android 12 起同样场景下 Activity 只会 onStop,不再执行 onDestroy。其他 Activity 点击返回键后行为不变,依然会 onDestroy
  • ViewModel 的销毁在 onDestroy 中,这样改动后 ViewModel 中的状态可以保存,再次启动后可以直接使用。对于使用者来说直接感受就是冷启动变为了热启动,启动速度更快。
Android12 之前的设备:
// 初次启动
D/SampleActivity: ON_CREATE
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME
// 返回桌面
D/SampleActivity: ON_PAUSE
D/SampleActivity: ON_STOP
D/SampleActivity: ON_DESTROY
// 再次启动
D/SampleActivity: ON_CREATE
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME

Android12 之后的设备:
// 初次启动
D/SampleActivity: ON_CREATE
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME
// 返回桌面
D/SampleActivity: ON_PAUSE
D/SampleActivity: ON_STOP
// 再次启动
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME

参考

我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值