个人学习记录
Android入门 第一关 四大组件
Activity
1. 生命周期
先上一张经典的生命周期图
Activity.java 注释中写到
<p>The entire lifecycle of an activity is defined by the following
* Activity methods. All of these are hooks that you can override
* to do appropriate work when the activity changes state. All
* activities will implement {@link android.app.Activity#onCreate}
* to do their initial setup; many will also implement
* {@link android.app.Activity#onPause} to commit changes to data and
* prepare to pause interacting with the user, and {@link android.app.Activity#onStop}
* to handle no longer being visible on screen. You should always
* call up to your superclass when implementing these methods.</p>
*
* </p>
* <pre class="prettyprint">
* public class Activity extends ApplicationContext {
* protected void onCreate(Bundle savedInstanceState);
*
* protected void onStart();
*
* protected void onRestart();
*
* protected void onResume();
*
* protected void onPause();
*
* protected void onStop();
*
* protected void onDestroy();
* }
思考:为什么要有生命周期?
An activity is a single, focused thing that the user can do. Almost all activities interact with the user
There are several other lifecycle callback methods that you should use in order to provide a fluid user experience between activities and handle unexpected interuptions that cause your activity to be stopped and even destroyed
Activity是单一专注的,能够与用户交互满足用户的需求;用户的需求越多,activity的实现也越多;为了更好的组织activity与activity之间、与应用之间、与系统之间等的关系,就需要实现生命周期,把activity管理起来,在需求切换时,根据不同的场景执行不同的操作,保证一个流畅的用户体验。
- onCreate()
* Called when the activity is first created.
* This is where you should do all of your normal static set up:
* create views, bind data to lists, etc. This method also
* provides you with a Bundle containing the activity's previously
* frozen state, if there was one.
生命周期开始的第一个方法,也只执行一次,activity开始被创建,执行一些初始化操作:installViewFactory()、ensureWindow()、还有一个parentActivityName,参考这里 等;
还有关键的 setContentView() :
@Override
public void setContentView(int resId) {
// 创建DecorView,设置给PhoneWindow
// Now set the Window's content view with the decor
// mWindow.setContentView(subDecor);
ensureSubDecor();
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
// 解析xml布局,生成View传给DecorView,
// 此时view还未绘制,window、activity也还未显示
LayoutInflater.from(mContext).inflate(resId, contentParent);
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
- onStart() 看看注释
/**
* Called after {@link #onCreate} — or after {@link #onRestart} when
* the activity had been stopped, but is now again being displayed to the
* user. It will usually be followed by {@link #onResume}. This is a good place to begin
* drawing visual elements, running animations, etc.
*
* <p>You can call {@link #finish} from within this function, in
* which case {@link #onStop} will be immediately called after {@link #onStart} without the
* lifecycle transitions in-between ({@link #onResume}, {@link #onPause}, etc) executing.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
* thrown.</em></p>
*
* @see #onCreate
* @see #onStop
* @see #onResume
*/
@CallSuper
protected void onStart(){
...
}
// onCreate 或 onRestart 方法之后就会调用 onStart
对于onStart之后activity的可见性,参考这里 我的理解就是恢复之前的可见状态,但并不是可交互。
- onRestart
* Called after {@link #onStop} when the current activity is being
* re-displayed to the user (the user has navigated back to it). It will
* be followed by {@link #onStart} and then {@link #onResume}.
activiy onStop之后重新恢复时会调用。
-
onResume 真正进行UI绘制的方法,准确来说是onResume调用完之后的代码逻辑进行绘制;主要通过WindowManager的addView方法;后续再分析;
-
onPause activity将被停止,失去焦点,不可交互,只有执行完下一个activity才被显示,所以不要在这里执行耗时操作。
-
onStop activity停止,变成不可见,不可交互;
Toast、Dialog、Menu、Dialog风格Activity、透明activity、非全屏activity不会触发onStop。
- onDestroy activity将被销毁
onStop/onDestroy 10s延迟问题参考 所以在这里释放资源也要仔细考虑判断好,而且被系统内存不足时杀死也会出现不执行的情况。
- onNewIntent
/** This is called for activities that set launchMode to "singleTop" in
* their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
* flag when calling {@link #startActivity}.
...
*/
protected void onNewIntent(Intent intent) {
}
只有singleTop模式的activity重复启动时会调用:onNewIntent-->onRestart-->onStart-->onResume。
- onSaveInstanceState
* The default implementation takes care of most of the UI per-instance
* state for you by calling {@link android.view.View#onSaveInstanceState()} on each
* view in the hierarchy that has an id, and by saving the id of the currently
* focused view (all of which is restored by the default implementation of
* {@link #onRestoreInstanceState}).
* 默认会调用设置了id的view的onRestoreInstanceState方法,并保存当前获取焦点的view的id
只有在特殊情况下才会执行的方法,可对一些需要恢复的状态、数据进行保存。
特殊情况:home键内存不足回收,横竖屏切换,语言切换;
这时activity会重走生命周期,需要处理数据丢失,Fragemnt 重叠等问题;
因为序列化会有很大的开销,又是在主线程,所以这里只适合保存少量的能支持序列化的数据,建议配合ViewModel使用(ViewModel源码关键:HolderFragment,setRetainInstance);
可以通过配置android:configChanges,来指定不响应哪些情况;
frameworks/base/core/res/res/values/attrs_manifest.xml 这里面可以查看configChanges取值;
在不同的 SDK 版本中,onSaveInstanceState调用时机是不一样的:
-- SDK 11 之前,在 onPause() 之前调用
-- SDK 28 之前,会在 onStop() 之前调用
-- SDK 28 之后,会在 onStop 之后调用
-
onRestoreInstanceState 只有在有数据需要恢复时才会被调用,onCreate()里也会有bundle参数,也可以用来恢复数据,但是要注意判空,两个方法的调用时机不同,根据需求决定在哪里进行恢复。
思考:怎么判断要执行哪一步生命周期的?
2. 任务栈
3. 启动模式
Activity启动时的策略,可以通过2种方式设置:
1、AndroidManifest.xml 中的标签 android:launchMode 设置
2、启动Activity时传入 Intent Flag:intent.setFlag()、intent.addFlag()
第2种方式的优先级比第1种高
launchMode 有以下4种取值:
-
Standard 标准模式,默认模式,每次启动都会新建一个activity实例,走完整的生命周期方法。
-
SingleTop 栈顶复用模式,会先判断待启动activity是否存在于栈顶:如果存在,则不会重新创建,而是复用,调用onNewIntent方法,不会调用onCreate、onStart,生命周期:onNewIntent-->onResume;不存在,则创建新的实例,走完整生命周期。
-
SingleTask 栈内复用模式,首先会查找待启动activity指定的任务栈(通过taskAffinity指定,没有则默认当前task):任务栈存在,则查找待启动activity是否存在于栈中,存在,则复用,生命周期:onNewIntent-->onResume,同时把在其之上的activity全部出栈;不存在,则创建新的实例,走完整生命周期流程;任务栈不存在,则创建对应的任务栈,然后创建新的实例入栈。 singleTask的实例也是全局唯一的。
-
SingleInstance 全局单一实例模式,首次启动创建实例,放入新的任务栈中,栈中有且只有这一个实例,后续不会创建其他新的实例。
Intent Flag 有以下几种常见取值(其余可在 frameworks/base/core/java/android/content/Intent.java 里查看):
-
Intent.FLAG_ACTIVITY_NEW_TASK 使用一个新的Task来启动一个Activity。不过单独给Activity的Intent设置Intent.FLAG_ACTIVITY_NEW_TASK是没有作用的,单独设置还是会创建新的实例;只有同时设置了taskAffinity时,行为才会和singleTask一致。
-
Intent.FLAG_ACTIVITY_SINGLE_TOP 等同于singleTop ,栈顶复用。
-
Intent.FLAG_ACTIVITY_CLEAR_TOP CLEAR_TOP 在单独使用时,如果想要的任务栈中已经存在待启动的 Activity 的实例,则会将该 Activity 实例之上的其他 Activity 弹出,把自己放到栈顶,并回调 onNewIntent 。但这是有前提的,就是待启动的 Activity 的 launchMode 不能是 standard 。 如果是 standard ,则会把自己及之上的所有 Activity 全部弹出,新建一个实例放入。
-
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具有这个标记的Activity不会出现在历史Activity列表中,相当于 android:exludeFromRecents="true"。
-
Intent.FLAG_ACTIVITY_NO_HISTORY 当该Activity启动其他Activity后,该Activity就被销毁了,不会保留在任务栈中。
adb shell dumpsys activity activities 此命令可以查看任务栈信息
4. Context
5. 启动流程
ActivityThread、ApplicationThread、WindowManager、ViewRootImpl、AMS、WMS、PMS、Binder、ServerManager、ActivityStack、Activity、Instrumentation、vsync 信号、SurfaceFlinger
6. 加载布局流程
Service
- 生命周期
- 启动方式
- 启动流程
Boardcast
- 生命周期
- 注册方式
- 类型
ContentProvider
- 使用方式