启动模式
Task
一组以栈的模式聚集在一起的Activity组件集合,Task之间的切换用户感知起来就像是每个独立的APP。一般地,最近任务列表中的某一个item(任务栈)有大于等于1个Task。
需要注意的是,如果按下home键,任务栈中的Task们则会出栈,分别占据一个任务栈
四种启动模式
standard(标准模式):不管有没有都会创建,会出现abcc这种
android:launchMode="standard"
singleTop(栈顶复用):在栈顶就复用,不在就创建(点击查看使用方法)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP android:launchMode="singleTop"
singleTask(栈内复用):在栈内就复用,而且会clearTop;在栈外就新建自己的任务栈,如果栈外存在该Activity则复用且clearTop,压在栈上(点击查看使用方法)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK android:launchMode="singleTask"
singleInstance(单例模式):单个Activity对应单个Task,且整个系统中只存在一个该Activity实例。如果打开则会新建自己的任务栈
android:launchMode="singleinstance"
相关规则默认情况下,启动新的Activity会直接进入当前Task。如果设置了
launchMode="singleTask"的Activity则会比较:
- 相同:正常入栈
- 不同:寻找与它相同的TaskAffinity入栈,没有的话就创建新Task相比之下,
standard、
singleTop适合在同一APP内操作,
singleTask更适用于两个不同的APP,
singleInstance则是看情况决定
其他属性
- TaskAffinity 表示activity与task的从属关系并不是由是否同一APP决定,而是由
TaskAffinity决定。一般一个application中的所有activity的
TaskAffinity是相同的,所以我们看到每个Task基本都是一个APP中的内容,我们可以通过设置更改Activity的
taskAffinity:
android:taskAffinity="com.test.TestActivity"
在最近任务列表中,相同的TaskAffinity最多只会显示一个
- allowTaskReparenting
表示这个Activity具有重新选择Task的性质。比如APP A打开B中的一个Activity,此时这个Activity会成为Task A中的一员。然而当我们打开B的时候,这时这个Activity会直接移动到Task B的顶部
Activity生命周期
OnCreate()
handleLaunchActivity()负责启动Activity前期的一些准备工作
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true; if (r.profilerInfo != null) { mProfiler.setProfiler(r.profilerInfo); mProfiler.startProfiling(); } if (r.mPendingFixedRotationAdjustments != null) { // The rotation adjustments must be applied before handling configuration, so process // level display metrics can be adjusted. overrideApplicationDisplayAdjustments(r.token, adjustments -> adjustments.setFixedRotationAdjustments(r.mPendingFixedRotationAdjustments)); } // Make sure we are running with the most recent config. mConfigurationController.handleConfigurationChanged(null, null); if (localLOGV) Slog.v( TAG, "Handling launch of " + r); // Initialize before creating the activity if (ThreadedRenderer.sRendererEnabled && (r.activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { HardwareRenderer.preload(); } // 初始化WindowManagerGlobal,便于之后的窗口展示 WindowManagerGlobal.initialize(); // Hint the GraphicsEnvironment that an activity is launching on the process. GraphicsEnvironment.hintActivityLaunch(); final Activity a = performLaunchActivity(r, customIntent); if (a != null) { r.createdConfig = new Configuration(mConfigurationController.getConfiguration()); reportSizeConfigurations(r); if (!r.activity.mFinished && pendingActions != null) { pendingActions.setOldState(r.state); pendingActions.setRestoreInstanceState(true); pendingActions.setCallOnPostCreate(true); } } else { // If there was an error, for any reason, tell the activity manager to stop us. ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED, null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } return a; }
performLaunchActivity()是启动Activity的核心会创建ContextImpl,创建Activity以及
Activity#attach(),最后回调
Activity#OnCreate()
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); } // 从AMS交互获取一系列的信息 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); } ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); // Instrumentation最终会通过反射创建Activity activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo), appContext.getAttributionSource()); 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 (localLOGV) Slog.v(TAG, "Performing launch of " + r); if (localLOGV) Slog.v( TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); // updatePendingActivityConfiguration() reads from mActivities to update // ActivityClientRecord which runs in a different thread. Protect modifications to // mActivities to avoid race. synchronized (mResourcesManager) { mActivities.put(r.token, r); } if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mConfigurationController.getCompatConfiguration()); if (r.overrideConfig != null) { config.updateFrom(r.overrideConfig); } if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } // Activity resources must be initialized with the same loaders as the // application context. appContext.getResources().addLoaders( app.getResources().getLoaders().toArray(new ResourcesLoader[0])); appContext.setOuterContext(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, window, r.configCallback, r.assistToken, r.shareableActivityToken); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; checkAndBlockForNetworkAccess(); activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } if (r.mActivityOptions != null) { activity.mPendingOptions = r.mActivityOptions; r.mActivityOptions = null; } activity.mLaunchedFromBubble = r.mLaunchedFromBubble; activity.mCalled = false; // Assigning the activity to the record before calling onCreate() allows // ActivityThread#getActivity() lookup for the callbacks triggered from // ActivityLifecycleCallbacks#onActivityCreated() or // ActivityLifecycleCallback#onActivityPostCreated(). r.activity = activity; // 唤醒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()"); } mLastReportedWindowingMode.put(activity.getActivityToken(), config.windowConfiguration.getWindowingMode()); } r.setState(ON_CREATE); } 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; }
Activity#attach()在attach中创建了实例化了Window(PhoneWindow)、windowManager(WindowManangerImpl),并且把它们关联起来了
(mWindowManager = mWindow.getWindowManager())
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, IBinder assistToken, IBinder shareableActivityToken) { attachBaseContext(context); mFragments.attachHost(null /parent/); mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(mWindowControllerCallback); 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; mAssistToken = assistToken; mShareableActivityToken = shareableActivityToken; 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; mWindow.setColorMode(info.colorMode); mWindow.setPreferMinimalPostProcessing( (info.flags & ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING) != 0); setAutofillOptions(application.getAutofillOptions()); setContentCaptureOptions(application.getContentCaptureOptions()); }
回调onCreate()
在现在的版本我们的Activity都是继承AppCompatActivity,AppCompatActivity的onCreate()是它的父类中的,它有构造函数主要是加载Factory、AppCompatDelegate,通过这些来适配Activity,以及替换AppcompatView
在Activity没有构造函数,onCreate()方法主要是和Actionbar和savedInstanceState转Parcelable存储相关
构造函数
通过new Activity后,我们首先会进入到构造函数,先看看
AppCompatActivity类的初始化
public AppCompatActivity() { super(); initDelegate(); }
private void initDelegate() { // TODO: Directly connect AppCompatDelegate to SavedStateRegistry getSavedStateRegistry().registerSavedStateProvider(DELEGATE_TAG, new SavedStateRegistry.SavedStateProvider() { @NonNull @Override public Bundle saveState() { Bundle outState = new Bundle(); getDelegate().onSaveInstanceState(outState); return outState; } }); addOnContextAvailableListener(new OnContextAvailableListener() { @Override public void onContextAvailable(@NonNull Context context) { final AppCompatDelegate delegate = getDelegate(); delegate.installViewFactory(); delegate.onCreate(getSavedStateRegistry() .consumeRestoredStateForKey(DELEGATE_TAG)); } }); }
AppCompatDelegateImpl#installViewFactory(), 来初始化LayoutInflater.Factory2
public void installViewFactory() { LayoutInflater layoutInflater = LayoutInflater.from(mContext); if (layoutInflater.getFactory() == null) { LayoutInflaterCompat.setFactory2(layoutInflater, this); } else { if (!(layoutInflater.getFactory2() instanceof AppCompatDelegateImpl)) { Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed" + " so we can not install AppCompat's"); } } }
AppCompatDelegateImpl.onCreate(savedInstanceState)
@Override public void onCreate(Bundle savedInstanceState) { // attachBaseContext will only be called from an Activity, so make sure we switch this for // Dialogs, etc mBaseContextAttached = true; // Our implicit call to applyDayNight() should not recreate until after the Activity is // created applyDayNight(false); // We lazily fetch the Window for Activities, to allow DayNight to apply in // attachBaseContext ensureWindow(); if (mHost instanceof Activity) { String parentActivityName = null; try { parentActivityName = NavUtils.getParentActivityName((Activity) mHost); } catch (IllegalArgumentException iae) { // Ignore in this case } if (parentActivityName != null) { // Peek at the Action Bar and update it if it already exists ActionBar ab = peekSupportActionBar(); if (ab == null) { mEnableDefaultActionBarUp = true; } else { ab.setDefaultDisplayHomeAsUpEnabled(true); } } // Only activity-hosted delegates should apply night mode changes. addActiveDelegate(this); } mEffectiveConfiguration = new Configuration(mContext.getResources().getConfiguration()); mCreated = true; }
AppCompatDelegateImpl构造之后,一般我们会调用setContentView()
AppCompatActivity的setContentView()
两者的区别就是分别从AppCompatDelegateImpl,PhoneWindow开始LayoutInflater.from(mContext).inflate(resId, contentParent);
AppCompatActivity中的构造函数会初始化Factory,从而替换View
Factory,Factory2只是两个接口,只有onCreateView方法
AppCompatDelegateImpl#setContentView
public void setContentView(int resId) { // 创建DecorView ensureSubDecor(); ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); LayoutInflater.from(mContext).inflate(resId, contentParent); mAppCompatWindowCallback.getWrapped().onContentChanged(); }
LayoutInflaterCompat#inflate()
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot(root != null)) { synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final Context inflaterContext = mContext; final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context) mConstructorArgs[0]; mConstructorArgs[0] = inflaterContext; View result = root; try { advanceToRootNode(parser); final String name = parser.getName(); if (DEBUG) { System.out.println(""); System.out.println("Creating root view: " + name); System.out.println(""); } if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { throw new InflateException(" can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } rInflate(parser, root, inflaterContext, attrs, false); } else { // Temp is the root view that was found in the xml final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } } if (DEBUG) { System.out.println("-----> start inflating children"); } // Inflate all children under temp against its context. rInflateChildren(parser, temp, attrs, true); if (DEBUG) { System.out.println("-----> done inflating children"); } // We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; } } } catch (XmlPullParserException e) { final InflateException ie = new InflateException(e.getMessage(), e); ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } catch (Exception e) { final InflateException ie = new InflateException( getParserStateDescription(inflaterContext, attrs) + ": " + e.getMessage(), e); ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; Trace.traceEnd(Trace.TRACE_TAG_VIEW); } return result; } }
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) { if (name.equals("view")) { name = attrs.getAttributeValue(null, "class"); } // Apply a theme wrapper, if allowed and one is specified. if (!ignoreThemeAttr) { final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME); final int themeResId = ta.getResourceId(0, 0); if (themeResId != 0) { context = new ContextThemeWrapper(context, themeResId); } ta.recycle(); } try { // 替换view为AppCompatView View view = tryCreateView(parent, name, context, attrs); if (view == null) { final Object lastContext = mConstructorArgs[0]; mConstructorArgs[0] = context; try { if (-1 == name.indexOf('.')) { view = onCreateView(context, parent, name, attrs); } else { view = createView(context, name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; } } return view; } catch (InflateException e) { throw e; } catch (ClassNotFoundException e) { final InflateException ie = new InflateException( getParserStateDescription(context, attrs) + ": Error inflating class " + name, e); ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } catch (Exception e) { final InflateException ie = new InflateException( getParserStateDescription(context, attrs) + ": Error inflating class " + name, e); ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } }
public final View tryCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) { if (name.equals(TAG_1995)) { // Let's party like it's 1995! return new BlinkLayout(context, attrs); } View view; if (mFactory2 != null) { view = mFactory2.onCreateView(parent, name, context, attrs); } else if (mFactory != null) { view = mFactory.onCreateView(name, context, attrs); } else { view = null; } if (view == null && mPrivateFactory != null) { view = mPrivateFactory.onCreateView(parent, name, context, attrs); } return view; } 之前setFactory()是AppCompatDelegateImpl。在这些其中我们还可以进行一些比如换肤之类的操作 public View createView(View parent, final String name, @NonNull Context context, @NonNull AttributeSet attrs) { if (mAppCompatViewInflater == null) { TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme); String viewInflaterClassName = a.getString(R.styleable.AppCompatTheme_viewInflaterClass); if (viewInflaterClassName == null) { // Set to null (the default in all AppCompat themes). Create the base inflater // (no reflection) mAppCompatViewInflater = new AppCompatViewInflater(); } else { try { Class<?> viewInflaterClass = mContext.getClassLoader().loadClass(viewInflaterClassName); mAppCompatViewInflater = (AppCompatViewInflater) viewInflaterClass.getDeclaredConstructor() .newInstance(); } catch (Throwable t) { Log.i(TAG, "Failed to instantiate custom view inflater " + viewInflaterClassName + ". Falling back to default.", t); mAppCompatViewInflater = new AppCompatViewInflater(); } } } boolean inheritContext = false; if (IS_PRE_LOLLIPOP) { if (mLayoutIncludeDetector == null) { mLayoutIncludeDetector = new LayoutIncludeDetector(); } if (mLayoutIncludeDetector.detect(attrs)) { // The view being inflated is the root of an d view, so make sure // we carry over any themed context. inheritContext = true; } else { inheritContext = (attrs instanceof XmlPullParser) // If we have a XmlPullParser, we can detect where we are in the layout ? ((XmlPullParser) attrs).getDepth() > 1 // Otherwise we have to use the old heuristic : shouldInheritContext((ViewParent) parent); } } return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext, IS_PRE_LOLLIPOP, /* Only read android:theme pre-L (L+ handles this anyway) / true, / Read read app:theme as a fallback at all times for legacy reasons / VectorEnabledTintResources.shouldBeUsed() / Only tint wrap the context if enabled */ ); }
AppCompatViewInflater.createView
final View createView(View parent, final String name, @NonNull Context context, @NonNull AttributeSet attrs, boolean inheritContext, boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) { final Context originalContext = context; // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy // by using the parent's context if (inheritContext && parent != null) { context = parent.getContext(); } if (readAndroidTheme || readAppTheme) { // We then apply the theme on the context, if specified context = themifyContext(context, attrs, readAndroidTheme, readAppTheme); } if (wrapContext) { context = TintContextWrapper.wrap(context); } View view = null; // We need to 'inject' our tint aware Views in place of the standard framework versions switch (name) { case "TextView": view = createTextView(context, attrs); verifyNotNull(view, name); break; case "ImageView": view = createImageView(context, attrs); verifyNotNull(view, name); break; case "Button": view = createButton(context, attrs); verifyNotNull(view, name); break; case "EditText": view = createEditText(context, attrs); verifyNotNull(view, name); break; case "Spinner": view = createSpinner(context, attrs); verifyNotNull(view, name); break; case "ImageButton": view = createImageButton(context, attrs); verifyNotNull(view, name); break; case "CheckBox": view = createCheckBox(context, attrs); verifyNotNull(view, name); break; case "RadioButton": view = createRadioButton(context, attrs); verifyNotNull(view, name); break; case "CheckedTextView": view = createCheckedTextView(context, attrs); verifyNotNull(view, name); break; case "AutoCompleteTextView": view = createAutoCompleteTextView(context, attrs); verifyNotNull(view, name); break; case "MultiAutoCompleteTextView": view = createMultiAutoCompleteTextView(context, attrs); verifyNotNull(view, name); break; case "RatingBar": view = createRatingBar(context, attrs); verifyNotNull(view, name); break; case "SeekBar": view = createSeekBar(context, attrs); verifyNotNull(view, name); break; case "ToggleButton": view = createToggleButton(context, attrs); verifyNotNull(view, name); break; default: // The fallback that allows extending class to take over view inflation // for other tags. Note that we don't check that the result is not-null. // That allows the custom inflater path to fall back on the default one // later in this method. view = createView(context, name, attrs); } if (view == null && originalContext != context) { // If the original context does not equal our themed context, then we need to manually // inflate it using the name so that android:theme takes effect. view = createViewFromTag(context, name, attrs); } if (view != null) { // If we have created a view, check its android:onClick checkOnClickListener(view, attrs); backportAccessibilityAttributes(context, view, attrs); } return view; }
Activity的setContentView()
public void setContentView(@LayoutRes int layoutResID) { // Window的唯一实现类是PhoneWindow getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }
actionBar跳过,actionBar其中有一句window.getDecorView(),锁定了Window的特征标志。Window的唯一实现类是PhoneWindow
,看PhoneWindow#setContentView(layoutResID)
public void setContentView(int layoutResID) { // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { // 走向和AppCompatActivity一样的路,只不过mFactory==null,不会去替换 mLayoutInflater.inflate(layoutResID, mContentParent); } mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } mContentParentExplicitlySet = true; }
总结一下
onCreate
- 首先会执行onCreate()方法中的 getDelegate() 创建一个AppCompatDelegate,AppCompatDelegate的实现类为AppCompatDelegateImpl
- AppCompatDelegateImpl#installViewFactory(), 来初始化LayoutInflater.Factory2
- Factory2创建view
- AppCompatDelegateImpl#onCreate(),版本适配
- AppCompatDelegateImpl#setContentView()创建DecorView,初始化布局(Activity在PhoneWindow#setContentView实现)
- AppCompatDelegateImpl#ensureSubDecor()-> createSubDecor()-> PhoneWindow#setContentView(View)->installDecor()->generateLayout()来创建mSubDecor,初始化布局
setContentView
- AppCompatDelegateImpl#setContentView
- setContentView#LayoutInflater.from(mContext).inflate(resId, contentParent)
- from#ContextImpl.getSystemService() 注册,LayoutInflater初始化
- LayoutInflater#createViewFromTag()
- mFactory2.onCreateView()或反射返回view
onStart
handleStartActivity
onResume
DecorView添加到windowManager
ViewRootImpl创建 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl开始绘制
Decorview.visiable
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
// skip below steps for double-resume and r.mFinish = true case.
// 入口
if (!performResumeActivity(r, finalStateRequest, reason)) {
return;
}
if (mActivitiesToBeDestroyed.containsKey(r.token)) {
// Although the activity is resumed, it is going to be destroyed. So the following
// UI operations are unnecessary and also prevents exception because its token may
// be gone that window manager cannot recognize it. All necessary cleanup actions
// performed below will be done while handling destruction.
return;
}
final Activity a = r.activity;
if (localLOGV) {
Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity
+ ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);
}
final int forwardBit = isForward
? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
willBeVisible = ActivityClient.getInstance().willActivityBeVisible(
a.getActivityToken());
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
// 添加decor到windowManager
a.mWindowAdded = true;
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r, false /* force */);
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
ViewRootImpl impl = r.window.getDecorView().getViewRootImpl();
WindowManager.LayoutParams l = impl != null
? impl.mWindowAttributes : r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
String reason) {
if (localLOGV) {
Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);
}
if (r.activity.mFinished) {
return false;
}
if (r.getLifecycleState() == ON_RESUME) {
if (!finalStateRequest) {
final RuntimeException e = new IllegalStateException(
"Trying to resume activity which is already resumed");
Slog.e(TAG, e.getMessage(), e);
Slog.e(TAG, r.getStateString());
// TODO(lifecycler): A double resume request is possible when an activity
// receives two consequent transactions with relaunch requests and "resumed"
// final state requests and the second relaunch is omitted. We still try to
// handle two resume requests for the final state. For cases other than this
// one, we don't expect it to happen.
}
return false;
}
if (finalStateRequest) {
r.hideForNow = false;
r.activity.mStartedActivity = false;
}
try {
r.activity.onStateNotSaved();
r.activity.mFragments.noteStateNotSaved();
checkAndBlockForNetworkAccess();
if (r.pendingIntents != null) {
deliverNewIntents(r, r.pendingIntents);
r.pendingIntents = null;
}
if (r.pendingResults != null) {
deliverResults(r, r.pendingResults, reason);
r.pendingResults = null;
}
// 入口
r.activity.performResume(r.startsNotResumed, reason);
r.state = null;
r.persistentState = null;
r.setState(ON_RESUME);
reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to resume activity "
+ r.intent.getComponent().toShortString() + ": " + e.toString(), e);
}
}
return true;
}
final void performResume(boolean followedByPause, String reason) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "performResume:"
+ mComponent.getClassName());
}
dispatchActivityPreResumed();
performRestart(true /* start */, reason);
mFragments.execPendingActions();
mLastNonConfigurationInstances = null;
getAutofillClientController().onActivityPerformResume(followedByPause);
mCalled = false;
// mResumed is set by the instrumentation
// 唤醒Resume,入口
mInstrumentation.callActivityOnResume(this);
EventLogTags.writeWmOnResumeCalled(mIdent, getComponentName().getClassName(), reason);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onResume()");
}
// invisible activities must be finished before onResume) completes
if (!mVisibleFromClient && !mFinished) {
Log.w(TAG, "An activity without a UI must call finish() before onResume() completes");
if (getApplicationInfo().targetSdkVersion
> android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
throw new IllegalStateException(
"Activity " + mComponent.toShortString() +
" did not call finish() prior to onResume() completing");
}
}
// Now really resume, and install the current status bar and menu.
mCalled = false;
mFragments.dispatchResume();
mFragments.execPendingActions();
onPostResume();
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPostResume()");
}
dispatchActivityPostResumed();
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
activity.onResume();
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i
final ActivityMonitor am = mActivityMonitors.get(i);
am.match(activity, activity, activity.getIntent());
}
}
}
}
ActivityThread #handleResumeActivity() r.activity.makeVisible();
这些handleXXXActivity应该都是AMS发送过来的由TransactionExecutor这个类处理
总结一下onResume
handleResumeActivity()
DecorView添加到windowManager。其中又包括了创建 ViewRootImpl,创建 Choreographer,与 WMS 进行 Binder 通信,注册 vsync 信号
ViewRootImpl创建 WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl开始绘制
Decorview.visiable
区分
onStart和
onStop是站在是否可见层面
onResume和
onPause是站在是否可交互层面
onDestory
主要就是做一些资源回收相关工作
@Override
public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
boolean getNonConfigInstance, String reason) {
performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);
cleanUpPendingRemoveWindows(r, finishing);
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;
if (v != null) {
if (r.activity.mVisibleFromServer) {
mNumVisibleActivities--;
}
IBinder wtoken = v.getWindowToken();
// 主要是做一些试图回收ViewRoot,window,decor等等的相关工作
if (r.activity.mWindowAdded) {
if (r.mPreserveWindow) {
// Hold off on removing this until the new activity's window is being added.
r.mPendingRemoveWindow = r.window;
r.mPendingRemoveWindowManager = wm;
// We can only keep the part of the view hierarchy that we control,
// everything else must be removed, because it might not be able to
// behave properly when activity is relaunching.
r.window.clearContentView();
} else {
final ViewRootImpl viewRoot = v.getViewRootImpl();
if (viewRoot != null) {
// Clear the callback to avoid the destroyed activity from receiving
// configuration changes that are no longer effective.
viewRoot.setActivityConfigCallback(null);
}
wm.removeViewImmediate(v);
}
}
if (wtoken != null && r.mPendingRemoveWindow == null) {
WindowManagerGlobal.getInstance().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
} else if (r.mPendingRemoveWindow != null) {
// We're preserving only one window, others should be closed so app views
// will be detached before the final tear down. It should be done now because
// some components (e.g. WebView) rely on detach callbacks to perform receiver
// unregister and other cleanup.
WindowManagerGlobal.getInstance().closeAllExceptView(r.token, v,
r.activity.getClass().getName(), "Activity");
}
r.activity.mDecor = null;
}
if (r.mPendingRemoveWindow == null) {
// If we are delaying the removal of the activity window, then
// we can't clean up all windows here. Note that we can't do
// so later either, which means any windows that aren't closed
// by the app will leak. Well we try to warning them a lot
// about leaking windows, because that is a bug, so if they are
// using this recreate facility then they get to live with leaks.
WindowManagerGlobal.getInstance().closeAll(r.token,
r.activity.getClass().getName(), "Activity");
}
// Mocked out contexts won't be participating in the normal
// process lifecycle, but if we're running with a proper
// ApplicationContext we need to have it tear down things
// cleanly.
Context c = r.activity.getBaseContext();
if (c instanceof ContextImpl) {
((ContextImpl) c).scheduleFinalCleanup(r.activity.getClass().getName(), "Activity");
}
if (finishing) {
ActivityClient.getInstance().activityDestroyed(r.token);
}
mSomeActivitiesChanged = true;
}
void performDestroyActivity(ActivityClientRecord r, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
Class activityClass = null;
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
activityClass = r.activity.getClass();
r.activity.mConfigChangeFlags |= configChanges;
if (finishing) {
r.activity.mFinished = true;
}
// 这里会发现,Destory前,如果Activity没有pause,stop,会先进行这些操作
// onResume与onPause,onStart与onStop成对出现的原因
performPauseActivityIfNeeded(r, "destroy");
if (!r.stopped) {
callActivityOnStop(r, false /* saveState */, "destroy");
}
if (getNonConfigInstance) {
try {
r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to retain activity "
+ r.intent.getComponent().toShortString() + ": " + e.toString(), e);
}
}
}
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnDestroy(r.activity);
if (!r.activity.mCalled) {
throw new SuperNotCalledException("Activity " + safeToComponentShortString(r.intent)
+ " did not call through to super.onDestroy()");
}
if (r.window != null) {
r.window.closeAllPanels();
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to destroy activity "
+ safeToComponentShortString(r.intent) + ": " + e.toString(), e);
}
}
r.setState(ON_DESTROY);
mLastReportedWindowingMode.remove(r.activity.getActivityToken());
// 清除资源IdleHandler
schedulePurgeIdler();
synchronized (this) {
if (mSplashScreenGlobal != null) {
mSplashScreenGlobal.tokenDestroyed(r.token);
}
}
// updatePendingActivityConfiguration() reads from mActivities to update
// ActivityClientRecord which runs in a different thread. Protect modifications to
// mActivities to avoid race.
synchronized (mResourcesManager) {
mActivities.remove(r.token);
}
StrictMode.decrementExpectedActivityCount(activityClass);
}
其实也有很大一部分是AMS侧做的事情。总结一下就是,在Destory前,AMS侧也会通知进行onPause,并且延迟500ms等待;这边调用 mStackSupervisor.activityIdleInternalLocked,在ActivityStack中对该Stop的stop该Destory的destory
finish()
// 通过Tag可以看出,我们在finish()的时候,不会停止任务
public void finish() {
finish(DONT_FINISH_TASK_WITH_ACTIVITY);
}
private void finish(int finishTask) {
if (mParent == null) {
int resultCode;
Intent resultData;
synchronized (this) {
resultCode = mResultCode;
resultData = mResultData;
}
if (false) Log.v(TAG, "Finishing self: token=" + mToken);
if (resultData != null) {
resultData.prepareToLeaveProcess(this);
}
// 这边就会通过AMS交互
if (ActivityClient.getInstance().finishActivity(mToken, resultCode, resultData,
finishTask)) {
mFinished = true;
}
} else {
mParent.finishFromChild(this);
}
// Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
// be restored now.
if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
restoreAutofillSaveUi();
}
}
public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
int finishTask) {
......
synchronized(this) {
// token 持有 ActivityRecord 的弱引用
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r == null) {
return true;
}
......
try {
boolean res;
final boolean finishWithRootActivity =
finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
// finishTask 参数是 DONT_FINISH_TASK_WITH_ACTIVITY,进入 else 分支
if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
|| (finishWithRootActivity && r == rootR)) {
res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
finishWithRootActivity, "finish-activity");
} else {
// 调用 ActivityStack.requestFinishActivityLocked()
res = tr.getStack().requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
}
return res;
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
这里为要finish的Activity设立标志位,然后直接切换到下个Activity。
if (index < (activities.size() - 1)) {
task.setFrontOfTask();
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
// If the caller asked that this activity (and all above it)
// be cleared when the task is reset, don't lose that information,
// but propagate it up to the next activity.
ActivityRecord next = activities.get(index+1);
next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
}