Android 四大组件之全面了解Activity

本文详细解释了Android中的Activity作为应用交互入口点的重要性和配置方法,包括主Activity和普通Activity的区别,以及如何通过Intent启动Activity(显示Intent和隐式Intent)。文章还涵盖了Activity的生命周期、启动模式和资源相关配置变化时的处理策略。
摘要由CSDN通过智能技术生成

Activity 的概念

Activity是应用与用户交互的入口点,它提供窗口供应用在其中绘制UI,这个窗口可能填满整个屏幕,也可能小于屏幕悬浮在其他窗口之上。通常来说一个应用会存在多个Activity,但只会存在一个主Activity(用户启动应用时显示的第一个Activity),然后每个Activity都可以启动另外的Activity以组成多屏幕的应用。

配置清单

如果要使用Activity,我们必须在AndroidManifest.xmk清单中配置,如下

<!--主Activity-->
<activity
    android:name=".activity.MainActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<!--正常Activity-->
<activity
    android:name=".activity.SecondActivity"
    android:exported="true">
</activity>

Activity启动

Activity的启动由Intent触发,其中Intent又分为显示Intent和隐式Intent,显示Intent可以明确的指向某一个Activity,隐式Intent则指向一个或多个Activity。一般来讲一个Intent不应该既是显示又是隐式,如果二者共存以显示为主。

显示Intent

属于精确匹配,有以下三种构建方式

1. 在Intent构造函数中指定
startActivity(Intent(this@MainActivity,SecondActivity::class.java))

2. 调用意图对象的setClass方法指定
   val intent = Intent()
   intent.setClass(this@MainActivity,SecondActivity::class.java)
   startActivity(intent)

3. 调用意图对象的setComponent方法指定
 val intent = Intent()
 val componentName  = ComponentName(this@MainActivity,SecondActivity::class.java)
 intent.setComponent(componentName)

隐式Intent

没有明确指定要跳转的目标Activity,通过IntentFilter匹配规则来指定跳转的Avtivity,过滤信息有action、category和data,如下所示是一个例子

<activity
    android:name=".activity.MainActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="com.abiao.action.a" />
        <action android:name="com.abiao.action.b" />
        <category android:name="com.abiao.category.a" />
        <category android:name="com.abiao.category.b" />
        <data android:mimeType="text/plain"/>
    </intent-filter>

    <intent-filter>
        <action android:name="com.abiao.action2.a" />
        <action android:name="com.abiao.action2.b" />
        <category android:name="com.abiao.category2.a" />
        <category android:name="com.abiao.category2.b" />
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>


一个Activity可以有一个或多个intent-filter,一个intent-filter可以有多个action、category和data,只要一个Intent同时匹配到一个intent-filter中的action、category和data就表示匹配成功,否则失败。

action 匹配规则
  1. action是一个字符串,系统有一些预定义的action,我们也可以在应用中定义自己的action。
  2. 匹配规则是字符串完全相同,区分大小写。
  3. Intent中只存在一个action。
  4. Intent中的action需要存在且和规则中的其中一个action相同,否则匹配失败。
category 匹配规则
  1. category是一个字符串,系统有一些预定义的category,我们也可以在应用中定义自己的category。
  2. 匹配规则是字符串完全相同,区分大小写。
  3. Intent中可以存在多个category。
  4. 匹配规则是Intent中任意一个category都能和category过滤规则中的其中一个匹配上。
  5. 如果Intent中没有category,依然能匹配成功,因为系统在调用startActivity或者startActivityForResulet的时候默认添加了android.intent.category.DEFAULT。
  6. 在匹配规则中我们需要添加android.intent.category.DEFAULT这个category
data 匹配规则

data的结构如下:

<data android:scheme="string"
      android:host="string"
      android:port="string"
      android:path="string"
      android:pathPattern="string"
      android:pathPrefix="string"
      android:mimeType="string"/>

data主要是由URI和mimeType组成

  1. mimeType指媒体类型(image/jepg、audio/mpeg4-generic和video/* 等表示图片、文本、视频),有默认值(content和File)

  2. URI 由以下结构

       <scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
    
    
    • scheme URI 模式,如http、file、content等,如果不指定则URI无效。
    • host URI 主机名,如www.baidu.com,如果不指定则无效
    • port URI 端口号,如 80
    • path 完整的路径信息
    • pathPattern 完整的路径信息,包含通配符*,*表示0个或者多个任意字符
    • pathPrefix 路径前缀信息
  3. 设置方法如下

intent.setDataAndType(Uri.parse(""),"image/png")  
//会将mimeType设置为null等价于intent.setDataAndType(Uri.parse(""),null)  
intent.setData(Uri.parse("file://abs"))  
//会将uri设置为null等价于intent.setDataAndType(null,"image/png")  
intent.setType("image/png")


  1. 匹配规则如下
  • data存在且只要匹配上规则上其中一条,表示匹配成功。
  1. 特殊写法,以下两种写法作用是一样的:
   <!--写法一-->
   <intent-filter>
        <data android:mimeType="text/plain" android:scheme="file" android:host="www.baidu.com"/>
    </intent-filter>
 <!--写法二-->
   <intent-filter>
        <data android:mimeType="text/plain"/>
        <data android:scheme="file"/>
        <data android:host="www.baidu.com"/>
    </intent-filter>

  1. 查找失败判断 通过隐式Intent启动Activity的时候可能会遇到找不到Activity的情况,这个时候系统会报错导致App崩溃,为了避免这种问题有以下两种方法可以判断是否存在Activty,如果这两个方法返回值不等于null,就可以启动成功。
    • PackageManager的resolveActivity(Intent,flags)方法,flags 需要MATCH_DEFAULT_ONLY这个标记位
    • Intent的resolveActivity

生命周期

正常情况下的生命周期

正常情况下,Activity会经历以下的生命周期

  1. onCreate

    表示Activity正在被创建,这里可以做一些初始化工作(加载界面布局资源,初始化Activity所需要的一些数据)

  2. onRestart

    表示Activity正在重新启动,当当前Activity从不可见变为可见状态时就会被调用

  3. onStart

    表示Activity正在被启动,这时候Activity已经可见但是还未出现在前台,无法与用户交互。

  4. onResume

    Activity已经可见,在前台出现并开始活动,可以与用户交互。

  5. onPause

    表示Activity正在停止,在正常情况下马上会调用onStop,但是在特殊情况下快速返回当前Activity,onReseume就会被调用,但这种情况很极端,用户很难遇见。这里可以做一些存储数据、停止动画之类的操作。但是不能太耗时,因为只有onPause执行完了新的Activity的onResume才会执行。

  6. onStop

    Activity即将停止,同样不能做太耗时工作,可以比onPause稍微重一点的任务

  7. onDestroy

    表示Activity即将销毁,这里可以做一些回收工作和最终的资源释放。

在这里插入图片描述

  • 注意
  1. 当用户打开了一个新的Activity,当前Activity回调如下:onPause -> onStop,但是当新的Activit是一个透明Activity时,当前Activity不会回调onStop.
  2. 当用户按下back键时,回调如下:onPause -> onStop -> onDestroy
  3. onCreate和onDestroy配对的,表示Activity的创建与销毁,整个生命周期中只调用一次。onStart和onStop也是配对的,便是Activity的可见与否,随着用户的操作或者屏幕点亮与否可能会回调多次。onResume和onPause也是配对的,表示Activity是否在前台。与onStart和onStop一样可能会被调用多次。

异常情况下的生命周期

Activity的生命周期除了受到用户操作影响之外也很可能因为资源相关的系统配置改变或者内存不足的时候被杀死。

资源相关的配置改变导致Activity被杀死并重建

资源相关配置会改变与系统的资源加载机制有关,举个例子,当我们把一张图片放在drawable目录后,可以通过Resource去获取,为了兼容不同设备我们可能会在其他目录(drawable-mdpi、drawable-hdpi、drawable-land等等),系统会根据不同的机型加载不同的Resource资源。但是假如Activity当前处于竖屏状态突然旋转屏幕,系统配置就发生了改变。默认情况下系统就会销毁当前Activity并重新创建。

这个时候当前Activity的生命周期如下: Activity生命名周期-异常情况下.png

系统资源被改变之后,Activity的onPause、onStop、onDestory会被调用,因为是异常终止所以,在onStop被调用之前系统会调用onSaveInstanceState来保存当前Activity的状态。Activity被重新创建之后,系统会把Activity销毁时在onSaveInstanceState中保存的Bundle对象作为参数传个onRestoreInstanceState和onCreate,因此我们可以通过onRestoreInstanceState和onCreate来判断Activity是否被重新创建了。onRestoreInstanceState的调用时机是在onStart之后。

资源改变时候我们可以通过配置configChanges这个属性来让Activity不重新创建

android:configChanges="orientation"

内存不足倒是低优先级的Activity被杀死

Activity的优先级

  • 前台Activty 正在和用户交互的Activity 优先级最高
  • 可见但非前台Activity
  • 后台Activity 已经被暂停了的Activity

当系统内存不足的时候,系统会按照以上优先级杀死目标Activity,并通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。

Activity启动模式

STANDARD 标准模式(默认)

每次启动都会重新创建一个新的Activity实例,不管当前实例是否存在。一个任务栈中可以存在多个实例,每个实例也可以属于不同的任务栈。谁启动了当前Activity那么这个Activity就在谁所在的那个任务栈当中。注意,如果是非Activity(如ApplicationContext)类型的Context去启动了一个新Activity会报错,是因为ApplicationContext没有所谓的任务栈,要启动需要使用下面准备介绍的SINGLE_TASK启动模式

SINGLE_TOP 栈顶复用模式

如果要创建的Activity位于栈顶,那么将不会重新创建实例,同时会调用Activity的onNewIntent方法,当前Activity的onCreate、onStart方法不会被系统调用。假如创建的Activity不在栈顶,那么就会重新创建一个新的实例。

SINGLE_TASK 站内复用

一种单实例模式,只要Activity在任务栈中存在,多次去启动改Activity都不会重新创建实例,同时和SINGLE_TOP一样会调用它的onNewIntent方法。当用该模式启动之后,系统会寻找是否存在其想要的任务栈,如果不存在则创建新的任务栈正常创建其实例,如果存在则将其实例调到栈顶并复用(调用其onNewIntent方法)。

SINGLE_INSTANCE 单实例模式

加强版的SINGLE_TASK,具有SINGLE_TASK的所有特性,另外具有此模式的Activity只能独立位于单独的任务栈中。由于SINGLE_TASK的特性,通过其创建的Activity都位于这个任务栈内,且只能存在一个实例。

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值