首页 > 其他分享 >Android进阶笔记-7. Context详解

Android进阶笔记-7. Context详解

时间:2022-10-09 20:34:15浏览次数:66  
标签:进阶 Activity ContextImpl intent Context activity Android null

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
  • Activity的attach方法调用了ContextThemeWrapper的attachBaseContext方法
;

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:
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
  • 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
  • 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
  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

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

标签:进阶,Activity,ContextImpl,intent,Context,activity,Android,null
From: https://blog.51cto.com/u_15501625/5741395

相关文章

  • Android——application全局类的使用
    目录 ​​1.概述​​​​2.Application基类​​​​3.自定义Application类​​​​4.Application的生命周期​​​​5.Application对象的回调函数​​​​6.Application对......
  • Android日志的过滤方法
    Android应用启动之后,有时候根据项目需要,我们只需要指定的日志,过滤掉多余的日志,方式如下......
  • Android RecyclerView的ItemAnimator (item的刷新动画)
    前言notifyItemChanged()在更新的时候会执行ItemAnimator动画,默认是闪烁的动画,此动画可以自定义。取消默认闪烁动画valanimator=mBinding.applyList.it......
  • android download hosts 域名解析
    203.208.40.97dl.google.com203.208.40.33dl.l.google.com74.125.137.91dl-ssl.google.com......
  • Android dialog使用案例
    需求:应用锁,//自定义dialog的显示viewViewview=getLayoutInflater().inflate(R.layout.passwd_dialog_view,null);finalEditTexteditText=(EditText)view.findV......
  • ​大数据面试题——Flink面试进阶篇
    1FlinkJob的提交流程用户提交的FlinkJob会被转化成一个DAG任务运行,分别是:StreamGraph、JobGraph、ExecutionGraph,Flink中JobManager与TaskManager,JobManager与Client的交......
  • Scanner进阶使用
    代码1//Java-零基础学习/src/process/Demo02packageprocess;​importjava.util.Scanner;​publicclassDemo02{  publicstaticvoidmain(String[]args){ ......
  • Android开发 Jetpack compose 配置开发环境
    前言 JetpackCompose是用于构建原生Android界面的新工具包。它可简化并加快Android上的界面开发,使用更少的代码、强大的工具和直观的KotlinAPI,快速打造生动......
  • ServletConfig、ServletContext概述、配置及ServletContext的三个作用
    目录​​一、ServletConfig概述​​​​二、ServletConfig配置​​​​三、ServletContext概述​​​​四、ServletContext配置​​​​五、ServletContext的三个作用​​一......
  • 优维低代码:Context 上下文
    导语优维低代码技术专栏,是一个全新的、技术为主的专栏,由优维技术委员会成员执笔,基于优维7年低代码技术研发及运维成果,主要介绍低代码相关的技术原理及架构逻辑,目的是给广大......