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區別?
- 從Activity中啟動新的Activity時可以直接mContext.startActivity(intent)就好,如果從其他Context中啟動Activity則必須給intent設置Flag:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ;
mContext.startActivity(intent);
原理:
- 首先startActivity是Context中的抽象方法
public abstract void startActivity(@RequiresPermission Intent intent);
- ContextWrapper中是調用了mBase的,也就是ContextImpl的實現
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
- 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);
}
- ContextThemeWrapper中沒有實現此方法
- 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
參考
我是今陽,如果想要進階和了解更多的干貨,歡迎關注wxgzh “今陽說” 接收我的最新文章