Android的Activity知识点总结


更新2020年10月13日11:55:42:3.5中增加了用代码设置启动方式的内容

前言

参考项目:https://github.com/wodongx123/ActivityDemo/tree/master
仅供参考,都是正文的代码。

1. Activity的定义

Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务。

2.Activity的生命周期

2.1任务和返回栈

  1. Android实际上使用任务(task)来管理Activity,每一个任务就是一个返回栈(back stack)。任务是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(即返回栈)中。
  2. 每当启动一个新的Activity的时候,这个新activty就会入栈。
  3. 一般情况下(也就是无任何其他因素影响的情况下),在点击手机的返回键的时候栈顶的Activity就会出栈,同时这个Activity也会被销毁。

2.2运行状态

  运行状态(Running):当一个Activity处于栈顶的时候,就是处于运行状态了,对于Android系统而言,它不会愿意强制销毁这样的进程。

  暂停状态(Paused):当Activity不处于栈顶,但是仍然可见的时候,就是处于暂停状态了。对于Android系统而言,哪天内存非常吃紧的时候,它会强制回收处于暂停状态的Activity。
  这样子想理解可能特别痛苦,简单的举例:处于栈顶的Activity(也就是运行状态的activty)忽然间弹出了一个对话框(实际上并不是对话框,而是一个并不占满全屏的Activity),大家都清楚,对话框一般不会铺满整个屏幕,此时Activity仍然有部分可见,这个时候这个Activity就进入暂停状态了。

  停止状态(Stopped):当Activity不处于栈顶,且完全不可见的时候,就是处于停止状态了。停止状态下的Activity不会被回收,其中的变量和状态都会保存。对于Android系统而言,哪天内存有些吃紧的时候,它会强制回收处于停止状态的Activity。

  销毁状态(Killed):当Activity从返回栈中移除之后,就是处于销毁状态了。对于Android系统而言,它正在回收分配给这个Activity的内存。

2.3生命周期

2.3.1生命周期方法

  onCreate():Activity被创建的时候调用,初始化Activity所需要的控件、布局、资源和事件等。
  onStart():此时Activity对于用户可见,但是不能交互。
  onResume():当Activity准备好和用户交互的时候调用,此时Activity一定处于返回栈的栈顶。
  onPause():Activity因为各式各样的原因(比如切回到桌面,比如打开新的Activity)即将变得不可见的时候,会调用这个方法。
  onStop():Activity完全不可见的时候调用,此时Activity对于用户就是完全不可见了。
  onRestart():当Activity要从不可见状态重新变成可见状态时,会在onStart()之前调用这个方法,也就是重新启动活动。
  onDestroy():Activity要完全被销毁的时候调用,之后Activity的实例将会消失。
随处可见的生命周期图
结合刚才的运行状态就可以得知:
在onResume()之后Activity处于运行状态
在onPause()之后Activity处于暂停状态
在onStop()之后Activity处于停止状态
在onDestroy()的时候activtiy处于销毁状态

2.3.2生命周期情况分析

单独Activity分析
  1. acitivity启动:onCreate() --> onStart() --> onResume() -->Activity正在运行
  2. Activity暂停:运行状态 --> onPause()
  3. Activity停止:运行状态 --> onPause() --> onStop() --> Activity完全不可见
  4. Activity重启:停止状态 --> onRestart() -->onStart() --> onResume() -->Activity正在运行
  5. Activity销毁:运行状态–> onPause() --> onStop() --> onDestroy() --> 系统回收内存
多个Activity分析
  1. 从Activity_A中启动Activity_B
    activtiy_A:3
    Activity_B:1
    具体顺序为:A onPause -> B onCreate -> B onStart -> B onResume -> A onStop
  2. 从Activity_B点击返回键回到Activity_A
    Activity_A:4
    Activity_B:5
onSaveInstanceState和onRestoreInstanceState
  • 在生命周期方法中,只有onCreate()是带有参数的。这个参数就是Activity所设置的保护机制。每当Activity遇到了意外情况1被强制关闭的时候,Activity会在关闭的前一刻调用内部函数onSaveInstanceState(),我们可以通过重写这个方法,让Activity被回收的时候用bundle保存一些重要数据,bundle是一种类似字典一样的数据类型,通过key-value模式来保存数据。
  • 顺带一提,onSaveInstanceState()的执行时间(如果有执行)是在onStop()之后,onDestroy()之前。
  • 而当调用了onSaveInstanceState()之后,再次启动Activity的时候,就会调用onRestoreInstanceState(),可以发现这个参数和onCreate()参数名相同,而事实上也是如此,两者是同一个变量,也就是说无论是通过onCreate()还是onRestoreInstanceState()均能恢复数据。但是要注意的是,如果onSaveInstanceState()没有执行,那么onCreate()中的参数就会为空,因此在使用onCreate()恢复数据的时候要判断是否为空。
  • 顺带一提,onRestoreInstanceState()的执行时间(如果有执行)是在onStart()之后,onResume()之前。
    //每当Activity遇到意外情况的时候,重写这个方法来保存数据
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.i(TAG, "onSaveInstanceState: ");
        outState.putString("key0", "value0");
        outState.putInt("key1", 1);
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "onRestoreInstanceState: ");
    }
Activity的横竖屏切换

  对于不做任何特殊改动的Activity而言,横竖屏切换实际上会先销毁当前的Activity,然后再重新创建一个新的采用横屏布局的Activity。
所以生命周期为:Activity销毁 --> Activity创建
I/MainActivity: onPause:
I/MainActivity: onStop:
I/MainActivity: onSaveInstanceState:
I/MainActivity: onDestroy:
I/MainActivity: onCreate:
I/MainActivity: onStart:
I/MainActivity: onRestoreInstanceState:
I/MainActivity: onResume:

Activity的屏幕大小切换

  可能你会很好奇,手机屏幕一共就那么大,都是定死的东西,怎么可能切换屏幕大小呢。事实上,以前是不可以,但是现在的手机都有一个叫做分屏的功能,在分屏的情况下,屏幕大小只有原先的一半,这个时候屏幕大小就变动了;而分屏恢复成全屏又回再变动一次。
  在切换屏幕大小的时候,实际上也是先销毁当前Activity,再创建一个新的Activity。生命周期也是先走销毁,然后再重新创建。

只执行onPause()不执行onStop()的特殊情况2

  想要造成这种情况,我们需要在原本的Activity上启动一个不是全屏的Activity,新建一个DialogActiviy,然后在androidmanifest.xml中改变DialogActivity的类型为窗口类型。

 	<Activity 
 		android:name=".DialogActivity"
    	android:theme="@android:style/Theme.Dialog" >
    </Activity>

在原来的Activity中设置一个按钮,点击后打开dialogActivity,这个时候原先的Activity就只执行onPause()而不会执行onStop()。
生命周期如下:
MainActivity:onPause()
DialogActivity:onCreate() --> onStart() --> onResume()
顺便一提,在保持着打开两个Activity的状态下,意外切出(比如息屏,比如切回到桌面)时的生命周期如下:
I/DialogActivity: onPause:
I/MainActivity: onStop:
I/MainActivity: onSaveInstanceState:
I/DialogActivity: onStop:
I/DialogActivity: onSaveInstanceState:
然后,在此情况下强制关闭app的生命周期如下:
I/MainActivity: onDestroy:
I/DialogActivity: onDestroy:

Activity弹出Dialog、Activity下拉菜单栏

Dialog的弹出实际上并不影响Activity的生命周期,也就是说,如果Activity中弹出了一个Dialog,那么Activity不会调用任何生命周期中的方法。
下拉菜单栏实际上也不会影响Activity的生命周期。

Activity销毁却没有执行onDestroy()
  • 在任务栈中如果有多个Activity,然后从后台强制清除任务(就是从最近任务中强制关闭应用),这个时候,只会调用处于返回栈最下面的Activity的onDestroy(),其他的不会调用。
  • 如果有多个返回栈(就是启动了带有SingleInstance的Acitivity),只会调用当前返回栈最下面的Activity的onDestroy()

3.Activity的启动方式

  Andoird系统通过不同的Activity启动方式,来实现在不同的情况下,Activity有不同的用法。
  假设:有一个Activity_A和Activity_B,它们都有AB个按钮,点击A之后,会生成一个Activity_A;点击B之后,会生成一个Activity_B,初始状态是栈内只有一个Activity_A。

3.1标准模式(standard)

  标准模式(standard):每当生成一个新的Activity的时候,其实本质上是生成一个Activity的实例,这也就是说,你可以嵌套重复打开同一个Activity无数次。

  • Activity_A在点击A按钮后,会生成一个新的Activity_A,此时你的返回栈中就会有两个不同的Activity_A。
    A打开A

3.2栈顶复用模式(singleTop)

  栈顶复用模式(singleTop):复用的意思就是把这个Activity拿来继续用,而不生成一个新的来使用。当Activity处于返回栈顶的时候,如果再次生成一个相同的Activity时,它不会创建新的Activity,而是继续使用当前的这个Activity。
  当然如果这个Activity不在栈顶的时候,刚刚的一切就当无事发生,启动一个同样的Activity会生成一个新的实例。

  • 假设Activity_A使用栈顶复用模式。在Activity_A中点击A按钮后,不会生成一个新的Activity_A,此时返回栈只有一个Activity_A。
  • 假设Activity_A使用栈顶复用模式。在Activity_A中点击B按钮后,生成一个新的Activity_B,再点击Activity_B的A按钮,此时会生成一个新的Activity_A,返回栈内有两个Activity_A。
    A打开B再打开A

3.3栈内复用模式(singleTask)

  栈内复用模式(singleTask):复用的意思同上,根据名字知道,当Activity处于返回栈内的时候,如果再次生成一个新的Activity时,不会创建新的而是使用现有的Activity,使用方法是:把压在这个activty上面的所有其他的Activity出栈(也就是把他们都销毁),使得这个Activity处于栈顶。

  • 假设Activity_A使用栈内复用模式。在Activity_A中点击A按钮后,不会生成一个新的Activity_A,此时返回栈只有一个Activity_A。
  • 假设Activity_A使用栈内复用模式。在Activity_A中点击B按钮后,生成一个新的Activity_B,再点击Activity_B的A按钮,不会生成一个新的Activity_A,Activity_B出栈,返回栈内只剩下个Activity_A。
    在这里插入图片描述

3.4单例模式(singleInstance)

  单例模式(singleInstance):单例模式比较特殊,当创建一个单例模式的Activity的时候,程序会创建一个新的返回栈,且这个返回栈内有且只有它一个Activity。

  • 假设Activity_B处于单例模式。Activity_A点击B后,创建一个新的返回栈B,里面只有Activity_B,再点击A后,原先的返回栈A创建一个新的Activity_A。
  • 要注意的是,对于Android 的任务而言,没有特殊原因它不会特地的去切换返回栈,所以在点击返回键后,显示的不是Activity_B而是Activity_A。
    单例模式

3.5启动模式的设置方法

  1. 在AndroidManifest.xml文件中,修改Activity的启动模式属性launchMode即可。
<activity
    android:name=".Activity_A"
    android:launchMode="singleTop" >
</activity>
  1. 在startActivity时指定flag设置启动模式
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 指定为singleTask启动模式
//intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); // 指定为singleTop启动模式
//intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 启动时,同一个任务栈上面的所有Activity都会出栈,一般和singleTask一起出现
//intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); // 该Activity不会出现在历史Activity列表中
startActivity(intent);

4.其他

横竖屏切换的补充说明

一般情况下,想要开启横屏模式的Activity,首先创建一个layout-land文件夹。

  1. 将Android项目切换成Project模式。
  2. app -> src - > main -> res -> new directory,取名叫layout-land。
  3. 然后将你想要横屏的activity的对应xml重写,命名为同名(比如说原本是activity_main.xml,那么在layout-land目录下的文件也叫activity_main.xml)。
  4. 要注意,原本xml上的控件在横屏之后不能缺失,不然在横屏后会报错(报空指针错误,因为找不到控件了…)。
  5. 这样一来,Android系统会在你将屏幕横过来之后,自动的切换到横屏模式。

一般这样设置完,在切换成横屏的时候,会自动销毁Activity,然后重新创建一个新的横屏模式的activity,但是,也有办法可以在不销毁的同时直接切换到横屏。
在AndroidManifest.xml中这么改。

 <application

	………………
	
     <!--android:configChanges可以在标出的情况发生时不重启Activity-->
     <activity
         android:name=".MainActivity"
         android:configChanges="orientation|screenSize">

		………………
		
     </activity>
 </application>

其中,orientation表示横竖屏切换,screenSize表示屏幕大小切换,两个一起加的原因是,横竖屏切换的同时,屏幕大小也会同时变化,所以要两个一起加才会在切换横竖屏的时候不重启Activity。
在设置之后,切换横竖屏不会调用任何生命周期方法。同时,使用分屏也不会调用任何生命周期方法了。
有关android:configChanges更多可以参考这篇:
https://blog.csdn.net/lkk790470143/article/details/79345971

执行onPause的补充说明

参考:Android 下拉通知栏时Activity的生命周期——重新理解onPause()
https://www.jianshu.com/p/781bc86f8042
结论:当且仅当Activity被另一个Activity所遮盖部分界面的时候,才会只执行onPause()不执行onStop()。

  • 不触发的情况举例:
    1. 打开Dialog。
    2. 弹出Toast。
    3. 下拉状态栏

统计Activity的各种时间

启动时间:在onCreate()和onResume()中记录时间,两者相减就是启动所花时间。
重启时间:在onRestart()和onResume()记录时间,相减。
工作时间:在onResume()和onPause()记录时间,相减。

选择后台的Activity销毁

有时候会出现这样的要求,用户现在在Activity_A,但是却要关闭处于后台的Activity_B,这种时候改怎么办呢。

  1. 对每个Activity都设置一个全局静态变量instance,然后在onCreate的时候将静态变量指向自己,这样在其他activity的话,也可以通过调用这个instance进行控制处于后台的Activity。但是这个方法不推荐使用,一是容易造成程序出错,二是不支持批量操作,如果我要同时关闭好几个Activity,那就很辛苦了。
  2. 封装一个ActivityController类,内部有一个List,每当有Activity启动的时候,就讲这个实例加入到List中,这样在要关闭的时候,只要从List中遍历就能找到要关闭的Activity了,而且也支持同时关闭所有Activity的功能(遍历所有的Activity关闭)。
  3. 一个采用弱引用的方法,本质上是方法1的解决内存泄漏后的改良版方法。
    Android在别的Activity关闭某个指定的Activity - CSDN
    https://blog.csdn.net/qq_36487432/article/details/82427753

参考材料

Android学习笔记(一) | Activity的生命周期 - 简书
https://www.jianshu.com/p/ec50675ed116
Android面试系列文章2018之Android部分Activity篇 - CSDN
https://blog.csdn.net/clandellen/article/details/79257489
第一行代码——Android(第2版)
p53 - p75


  1. onSaveInstanceState的调用情况可以看这篇:
    https://blog.csdn.net/wzy901213/article/details/79621944 ↩︎

  2. 只执行onPause()不执行onStop()参考这篇:
    https://blog.csdn.net/a872822645/article/details/62217965 ↩︎

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Android入门知识点总结: 1. Android基础知识: - Android是一个基于Linux的开源操作系统,主要用于移动设备。 - Android应用程序使用Java编程语言开发。 - Android应用程序由多个组件组成,包括活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)和内容提供者(Content Provider)。 2. Android应用程序的生命周期: - 活动(Activity)是Android应用程序的用户界面的基本构建块。活动有不同的生命周期状态,如创建、启动、暂停、恢复和销毁。 - 活动的生命周期由回调方法控制,如onCreate()、onStart()、onResume()、onPause()、onStop()和onDestroy()。 3. Android布局: - Android应用程序使用XML文件定义用户界面布局。 - 常用的布局类型包括线性布局(LinearLayout)、相对布局(RelativeLayout)、帧布局(FrameLayout)和约束布局(ConstraintLayout)。 4. Android资源管理: - Android应用程序使用资源文件来存储图像、字符串、颜色等非代码资源。 - 资源文件存储在res目录下,可以通过资源ID在代码中访问。 5. Android意图(Intent): - 意图用于在不同组件之间传递数据和执行操作。 - 显式意图(Explicit Intent)用于启动特定的组件,如活动。 - 隐式意图(Implicit Intent)用于执行系统级操作,如拨打电话、发送短信等。 6. Android存储: - Android应用程序可以使用内部存储和外部存储来保存数据。 - 内部存储用于保存应用程序私有数据,如数据库文件。 - 外部存储用于保存公共数据,如图片、音频和视频文件。 7. Android网络通信: - Android应用程序可以使用HTTP协议进行网络通信。 - 可以使用Android提供的HttpClient类或者使用第三方库,如OkHttp、Volley等。 8. Android数据库: - Android应用程序可以使用SQLite数据库进行数据存储。 - SQLite是一种轻量级的关系型数据库,适用于移动设备。 9. Android权限管理: - Android应用程序需要在清单文件中声明所需的权限。 - 权限用于保护用户的隐私和设备的安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值