Android四大组件之Activity

Android学习的第一步从四大组件开始


Activity是App用于人机交互的最常用的组件,往往用户操作都需要和Activity打交道(当然也有没有Activity的App)。
在开发过程中,可以对Activity的进行的操作一般在三个方面:

  • AndroidManifest.xml:1、注册Activity,只有注册过的Activity才能生效;2、注册Activity的属性。
  • Activity.java:关于Activity的相关代码实现,Activity的核心。
  • Layout.xml:设置Activity的显示样式,需要在Activity的onCreate()中使用。

说一点点
在AS中新建Activity时,系统会自动在生成 AndroidManifest.xml 进行注册,生成Activity.javaLayout.xml文件并关联。
本文涉及Activity的注册生命周期异常情况下的生命周期以及启动模式

1.注册

Activity 使用前必须在清单文件中注册,这样系统才能知道这里有一个Activity可以使用,才能访问它。

要注册 Activity需要打开 AndroidManifest.xml 文件进行注册,并将 元素添加为 元素的子项,至于 AndroidManifest.xml 文件是什么?怎么注册?来,我们看个饭粒:

<manifest xmls:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">
  <application 
        android:allowBackup="true"
        android:icon="@mipmap/ic_laucher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        
      <activity android:name=".MainActivity">
            <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
      </activity>
      <activity android:name=".OtherActivity"></activity>
      
  </application>
</manifest >

按照常规xml文件的类型来理解一下:根节点manifest就是我们当前的注册文件,其中有两个属性,一个声明了命名空间,另一个指定了包名。注册文件中有一个Application元素,Application保存5条相关属性,并且持有2个Activity元素。每个Activity有1个相关属性(这里有一个 后面会提到)。
这样看来 AndroidManifest.xml 文件,就是整个App的“结构树”和“配置说明”。

补充一点点:
AndroidManifest.xml 是每个android程序中必须的文件。它位于整个项目的根目录,描述了package中暴露的组件(activities, services, 等等),他们各自的实现类,各种能被处理的数据和启动位置。 除了能声明程序中的Activities, ContentProviders, Services, 和Intent Receivers,还能指定permissions和instrumentation(安全控制和测试)
引用自:Android的AndroidManifest.xml文件的详解

这样一想,注册Activity也就简单多了,就是在 <application/> 节点下添加一个<activity/> 节点,并且保证<activity/> 节点的android:name属性与相应的*.java文件保持一致。
但是,这样还不是结束,注意一下上面提到的节点

<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

当我在一个<application/> 节点下添加了多个<activity/> 节点时,这时在程序看来每一个<activity/> 在优先级上是没有区别的,那么在启动时应该启动哪个Activity?为了防止程序出现疑惑的情况,我们需要指定第一个被启动的Activity。

  • 标记有android.intent.action.MAIN的Activity会优先被程序启动。
  • 标记有android.intent.category.LAUNCHER决定了当前Activity会不会出现在程序列表中,生成一个程序入口。

在注册MainActivity时需要使用<intent-filter>进行声明,并且Main和LAUNCHER同时设定才有意义

补充一点点
当Application中设置多个包含Main和LAUNCHER的<intent-filter>,程序列表会出现多个图标分别对应不同的Activity入口,点击任何一个图标,则启动对应的Activity。
引用自:为多个Activity配置android.intent.category.LAUNCHER和android.intent.action.MAIN

2.生命周期

生命周期就是指一个对象的生老病死(从摇篮到坟墓的整个过程)。 ——百度百科

一直想找一个解释:Activity生命周期是什么?查了一下无非是“四大状态七大方法“,看着感觉解释很僵硬。就和下面的问答一样:
问:电脑是什么?
答:主机+显示器+…+键盘+鼠标。
嗯…说的很正确,但是好像感觉哪里不对劲?
PS:现在还是没有找到一个合适的解释,这里只是希望不要将“四(五)大状态七大方法“过度的分开理解,也不要按照的“生命周期图”的顺序死记硬背。

七大方法

Android四大组件之Activity

(1)onCreate():在Activity创建时调用,通常做一些初始化设置。

(2)onStart():在Activity准备显示在屏幕前调用,调用后Activity处于可见状态。

(3)onResume():在Activity获取焦点开始与用户交互时调用。

(4)onPause():表示Activity暂停,一般情况下onStop()会马上被调用。但是在当前Activity被其他Activity部分覆盖或锁屏时调用时仅调用onPause()。

(5)onStop():在Activity进入后台对用户处于不可见状态时调用。

(6)onDestroy():在Activity即将被销毁时调用。

(7)onRestart():在Activity从停止状态再次启动时调用,一般为用户行为导致。

五种状态

由图可视,以上为Activity的五种状态(Staring很短暂,可能直接合并到Staring,所以有的文章中为四种状态)

Android四大组件之Activity

1.Starting(启动状态):创建Activity,启动Activity进入Running
2. Running(运行状态):Activity位于任务栈顶部(当前可交互操作的Activity处于此状态)。
3. Paused(暂停状态):Activity处于可见状态,但是无法进行交互操作。
4. Stopped(停止状态):Activity完全不可见,但仍保留相关成员和数据。
5. Destroyed(销毁状态):Activity被销毁,等待被系统回收

状态转换过程(常规情况下)

  • 第一次启动(Activity(Starting ——>Running)
    onCreate() ->onStart() -> onResume
  • 启动其他 Activity(Running ——> Stopped|Paused)
    常规启动,原Activity会进入后台Stopped,但是如果只是被DialogActivity部分覆盖,或者被透明Activity覆盖,当前Activity会处于Paused。
  • 用户再次返回原Activity(Stopped——>Running或者Paused——>Running)
    onRestart() ->onStart() ->onResume() 或者 onResume()
  • 锁屏时只会调用onPause(),而不会调用onStop方法,进入Paused状态,开屏后则调用onResume()
  • home键返回主界面(Running ——> Stopped)
    onPause()——>onStop()
  • back键返回主界面(Running ——> Destroyed)
    onPuse()——>onStop()——>onDestory()

三个周期

Android四大组件之Activity

  • Activity 的整个生命周期发生在 onCreate() 调用与 onDestroy() 调用之间。 应在 onCreate() 中执行“全局”状态设置(例如定义布局),并在 onDestroy() 中释放所有的其余资源。例如,如果 Activity 有一个在后台运行的线程,用于从网络上下载数据,它可能会在 onCreate() 中创建该线程,然后在 onDestroy() 中停止该线程。
  • Activity 的可见生命周期发生在 onStart() 调用与 onStop() 调用之间。在这段时间,用户可以在屏幕上看到 Activity 并与其交互。 例如,当一个新 Activity 启动,并且此 Activity 不再可见时,系统会调用 onStop()。可以在调用这两个方法之间调用向用户显示 Activity 所需的资源。 在 Activity 的整个生命周期,当 Activity 在对用户可见隐藏两种状态中交替变化时,系统可能会多次调用onStart() 和 onStop()
  • Activity 的可操作生命周期发生在 onResume() 调用与 onPause() 调用之间。在这段时间,Activity 位于屏幕上的所有其他 Activity 之前,并具有用户输入焦点。 Activity 可频繁转入和转出前台 — 例如,当设备转入休眠状态(锁屏)或出现对话框时,系统会调用 onPause() 。 由于此状态可能经常发生转变,因此这两个方法中应采用适度轻量级的代码,以避免因转变速度慢而让用户等待。

3.异常情况下的生命周期

系统资源配置发生改变以及系统内存不足时,activity就可能被杀死。

  1. 如果Activity在异常情况下被终止,系统会调用onSaveInstance()来保存当前activity状态,这个方法的调用时机是在onStop()之前,与onPause()无必然时序关系。
  2. 当Activity需要被恢复时,系统会调用onRestoreInstanceState()来恢复原Activity,该方法在onStart()之后调用。

Android四大组件之Activity

补充一点点
1、系统本身会在异常恢复的过程中自动做一部分恢复工作,方法与Activity相同,每个view都实现了onSaveInstanceState()和onRestoreInstanceState()。
2、防止重新创建activity:activity指定configChange属性来不让系统重新创建activity。
例如:指定旋转屏幕时不重新创建:android : configChanges = "orientation"
PS:如果minSDKVersion & targetSDKVersion有任何一个大于13,则需要额外添加screenSize

4.Activity启动模式

activity有四种启动模式:standard、singleTop、singleTask、singleInstance
使用相应的启动模式时需要在manifest文件中声明:

<activity
    android:name=".OtherActivity"
    android:launchMode="singleTop">
</activity>

如上代码所示,如果设置OtherActivity的启动模式为singleTop,需要在该Activity对应的标签中添加属性(注意:是属性不是子Node)android:launchMode="singleTop"

(1)standard-默认模式

activity的默认启动模式。activity启动时默认重新实例化,进入启动它的activity所属的任务栈中,并且standard模式的activity可以被多次实例化。即在同一个任务中可以存在多个activity的实例。

补充一点点
在非Activity类型的context(如ApplicationContext)并没有所谓的任务栈,所以不能通过ApplicationContext去启动standard模式的Activity。

(2)singleTop-栈顶复用模式

如果以singleTop模式启动Activity,如果当前Activity已经有实例位于任务栈的栈顶,Activity不会被重新创建,而是回调它的onNewIntent方法。如果以singleTop模式启动的Activity的一个实例已经存在与任务桟中,但是不在桟顶,那么它的行为和standard模式相同,也会创建多个实例。

(3)singleTask-栈内复用模式

如果以singleTask模式启动Activity。那么在当前任务栈中,被启动的Activity只能存在一个实例,多次启动此Activity不会被重新创建单例,系统会回调onNewIntent。比如Activity A ,系统首先会寻找是否存在 A 想要的任务栈,如果没有则创建一个新的任务栈,然后把Activity A 压入栈,如果存在任务栈,然后再看看有没有 Activity A 的实例,如果实例存在,那么就会把A调到栈顶并调用它的 onNewIntent() 方法,并清除它当前所在任务中位于它上面的所有的activity使其位于栈顶,如果不存在则把它压入栈。

补充一点点
这里提到了 被启动的 Activity A 想要的任务栈 这里涉及 Activity 的一个新的属性 taskAffinity,有兴趣的请点这里解开Android应用程序组件Activity的"singleTask"之谜

(4)singleInstance-单例模式

  1. 以singleInstance模式启动的 Activity 具有全局唯一性,即整个系统中只会存在一个这样的实例
  2. 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何 Activity 都会运行在其他任务中。