四大组件

339 阅读7分钟

个人学习记录

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} &mdash; 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 之后调用

  • 参考1

  • 参考2

  • 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. 加载布局流程

Android 显示系统:SurfaceFlinger详解

Service

  1. 生命周期
  2. 启动方式
  3. 启动流程

Boardcast

  1. 生命周期
  2. 注册方式
  3. 类型

ContentProvider

  1. 使用方式