Android 四大组件之Activity

赵云
• 阅读 2349

前言

Hi,大家好,又见面啦,上一期我们讲了如何安装AS,是不是已经有小伙伴迫不及待的创建了自己的项目并开始尝试了呢?那么这一期我们主要为大家介绍Activity。作为Android的四大组件之一,Activity占据着非常重要的作用。本文将围绕Android的生命周期、启动模式、基本配置等方面进行介绍。

简介

应用程序的每一个界面都是一个Activity,所以也有人称其为视图界面。从字面的意思去理解,Activity具有活动的意思,我们在应用中进行的操作都是集中在Activity上面完成,例如拨号、拍照、发送email、看地图。每一个activity被给设置到一个窗口,在上面可以绘制交互界面。 一个应用程序通常由多个activities组成,他们通常是松耦合关系,通常一个应用程序包含有一个主Activity,即点击桌面图标的时候首先进入的Activity。

Android创建与启动

以一个简单的Activity的创建与使用示说明:

创建

Android 四大组件之Activity

在Androd Studio 新建项目完成后,会自动创建一个 Java 文件,这个文件就是 Activity,因为它继承系统 framework 层提供的 Activity,这里 AppCompatActivity 是 Activity 的子类,我们的 MainActivity 间接继承 Activity。

并且你会看到 MainActivity 强制重写了 onCreate 方法,在 onCreate 中,通过 setContentView 为 Activity 设置我们自定义的页面布局文件。

注册Activity

在 manifest 中注册Activity

     <activity
            android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            android:label="@string/app_name"
            android:launchMode="standard">
            <intent-filter>
                <action android:name="myactoin2" />
                
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
      </activity>

Activity 必须在 AndroidManifest.xml 注册,如果没有注册这 Activity 就不能正常运行,其实在正常情况下在使用Android 中的四大组件(Activity,Service,BrocastReceiver,ContentProvider)时都需要再 AndroidManifest.xml 中注册。在上面的 xml 注册信息中,其中 <inten-filter>中指定

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

表明这个Activity是主Activity,在Android系统点击应用图标首先进入主Activity。

启动

Activity是通过Intent用来在应用程序的Activity间启动、停止和传输。

启动Activity的三种方法:

1、显示启动

在这里注册了第二个Activity ---- SecondActivity ,并且牢记前面的注册操作,我们把 SecondActivity 注册到 Manifest 文件中。现在就可以在 MainActivity 中启动 SecondActivity。

Intent intent = new Intent(this, SecondActivity.class);
//通过上下文Context和SecondActivity.java类的Class对象,创建 Intent 对象 
startActivity(intent);//调用系统Framework 层提供的方法,启动 SecondActivity。

2、隐式启动

若 SecondActivity 在AndroidManifest.xml文件中配置 intent-filter 的 action 和 category、data,如下:

<intent-filter>    
   <action android:name="myaction2"/>    
   <category android:name="android.intent.category.DEFAULT"/>    
   <category android:name="mycategory" />
</intent-filter>

那么可以通过如下方式启动 SecondActivity :

Intent intent = new Intent("myaction2");
startActivity(intent);

3、默认启动

通过桌面图标点击应用图标进入程序的第一个Activity,因其启动方式有别上述两个方式,将其划分为第三类的启动方式。 若Activity在AndroidManifest.xml文件的intent-filter的action和category,如下:

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

那么,点击桌面的应用图标即可启动Activity。

注:如果在N个Activity中都配置上述的action和category,那么桌面会有N个应用的图标,点击不同的图标会进入对应的Activity。

Activity的生命周期

Activity 的生命周期如下图:

Android 四大组件之Activity

(1) onCreate

表示Activity正在被创建,这是第一个执行的方法,在Activity的生命周期中只执行一次。在这个方法中做一些初始化工作,比如调用setContentView去加载界面布局,初始化Activity所需要的数据等。后续调用onStart()。

(2) onRestart

表示Activity正在重新启动,一般情况下,当前的Activity从不可见的状态变为可见状态时,onRestart就会被调用。这种情形一般是用户操作出现所致,比如用户按Home键回到桌面或者用户打开了一个新的Activity,这时候Activity就会暂停,接着用户又回到该Activity。后续调用onStart()。

(3) onStart

表示Activity正在被启动,即将开始。这个时候Activity是可见的,但是还没有出现在前台,不能和用户进行交互。这个时候可以理解为Activity已经显示出来,但是我们还看不到。后续的方法是onResume()。

(4) onResume

表示Activity可见,并且已经出现在前台并开始活动,能和用户正常进行交互。需要注意的是onStart和onResume的区别,二者都是Activity可见,但是onStart时Activity还在后台,而onResume时Activity到了前台了,这时候可以开启动画或者获取独占性设备的操作如打开相机、获取麦克风等。

(5) onPause

表示Activity由前台转到后台,正常情况下,紧接着onStop就会被调用。这时仍然可见。如果这时候快速地回到当前Activity,那么onResume会被调用,这类情况属于极端情况,用户操作很难重现这一场景。此时可以做一些存储数据,停止动画等操作,但是注意不能太耗时,如果太耗时会影响到新的Activity的显示。onPause是先执行完,新的Activity的onCreate才会执行。onResume和onPause相对应。

(6) onStop

表示Activity即将停止,当前的Activity对用户不在可见。可稍微做些重量级的回收操作。后续的操作可能是onRestart或者onDestroy或者一直保持这个状态。

(7) onDestory

表示Activity正在被销毁,是生命周期的最后一个回调,也是只调用一次。发生的条件是Activity本身已经执行完毕,或者系统资源不足需要回收资源将Activity销毁。

我们考虑如下几类情况: 1、当一个Toast弹出的时候,会发生回调么? No 2、当一个AlertDialog弹出的时候,会发生回调么? No, 如果AlertDialog获取焦点,Activity会触发onWindowFocusChanged回调 3、当一个PopWindow弹出的时候,会发生回调么? No, 如果PopWindow获取焦点,如mPopupWindow.setFocusable(true),Activity会触发onWindowFocusChanged回调。 4.横竖屏切换时,会造成Activity被销毁然后重新创建。若在Activity配置android:configChanges="orientation",横竖屏切换时,只触发onConfigurationChanged( )回调,Activity不会被重新创建。

启动模式

Activity 有四种启动模式,不同的模式,对应这 Activity 对象的创建于复用策略,可以在 Manifest 和 代码中指定 Activity 的启动模式。

在探究什么是启动模式之前要弄请几个问题:

  1. 启动模式原理(什么是任务栈)?
  2. 为什么会需要启动模式?
  3. 四种任务栈的特点?
  4. 使用方式
  5. 应用场景
什么是任务栈

Android 任务栈又称为 Task,它是一个栈类型的数据结构:先进后出。它用于存储我们的 Activity 组件。

每次打开一个新的 Activity 或 退出一个 Activity 都会在任务栈的结构中添加或减少一个 Activity,一个任务栈包含了一个 Activity 集合。Android 系统可以通过 Task 有序的管理每个 Activity ,并决定那个 Activity 与用户进行交互:只用在栈顶的 Activity 才可以跟用户进行交互。

在应用程序退出时,必须把所有任务栈中的 Activity 清除栈时,任务栈才会被销毁。当然任务栈可以移动到后台,并且保存每个 Activity 的状态。可以有序的给用户列出Activity的任务,同时也不会丢失 Activity 的信息。

应用程序中可能不止一个任务栈,某系情况情况下,单独的一个 Activity 可以独享一个任务栈,也会存在一个任务栈的 Activity 可以来自不同的 App,同一个 App 中的 Activity 可能在不同的任务栈当中。

为什么会需要启动模式

在应用程序开发过程中,一般都需要在多个 Activity 组件之间跳转,也可能需要在本应用中打开其他应用的可复用的 Activity。在开发过程中需要跳转到原来已经开启的 Activity 实例,此时我们希望这个 Activity 可以被重用而不是再重新创建一个新的 Activity 实例,但根据 Android 系统的默认行为,每次都会为我们创建一个新的 Activity 实例对象并添加到任务栈中,而且 Activity 的数据和信息状态都将会被保留

我们可以在 MainActivity 中添加一个按钮,点击按钮跳转到 SecondActivity,然后在 SecondActivity 中添加两个按钮,点击一个按钮跳转到 MainActvity,在另一个按钮的点击事件中添加如下代码:

//获取ActivityMananger
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
//获取任务栈 可能是多个
List<ActivityManager.RunningTaskInfo> runningTasks = am.getRunningTasks(5);
//获取当前的任务栈
ActivityManager.RunningTaskInfo runningTaskInfo = runningTasks.get(0);
//获取当前任务栈中 Activity 个数,即当前没有换存活的 Activity 实例个数。
int numRunning = runningTaskInfo.numRunning;
//Log 打印信息
Log.e("SecondActivity", "numRunning" + numRunning);

上面代码不用深究,主要目的是想说明系统默认情况下,当前任务栈中存活的 Activity 实例个数。当我们在 MainActvity 中点击按钮跳转到 SecondActivity ,当跳转到 SecondActivity 在点击第一个按钮跳转到 MainActivity ,不断重复这个操作。最后当跳转的 SecondActivity 点击第一个按钮获取当前任务栈中的 Activity 个数。下面是方法和其对应运行时对应结果。

Android 四大组件之Activity

这样造成数据沉余,重复数据太多,最终可能还会导致内存溢出(OOM)。为解决这些问题,Android 系统提供了一套 Activity的启动模式来修改默认的 Activity 启动模式。

四种任务栈的特点
  • Standard 模式(一般模式)

系统默认模式,每次启动一个Activity都会重新创建一个新的实例,而不管Activity是否已经创建了一个实例。

  • SingTop (栈顶复用模式)

栈顶复用模式,系统启动时,系统会启动当前栈顶Activity是不是要启动的Activity,如果是则不需要创建新的Activity而直接引用这个Activity,如果不是那么创建新的Activity。系统会回调Activity的onNewIntent()的方法。

  • SingTask(栈内复用模式)

栈内复用模式,如果栈内已经存在了一个Activity的实例,那么Activity不会被重新创建,同时这个Activity的onNewIntent()方法会被回调,并将该Activity实例置于栈顶,原先处于该实例顶部的Activity实例会被出栈销毁。如果是其他程序启动Activity,那么它会重新创建一个任务栈。

  • SingleInstance(单一实例模式)

单实例模式,是singleTask的加强版,具有singleTask所有特点,并且此种模式下Activity只有一个实例,并且只能单独的存在一个任务栈中。

使用方式

启动模式一般分为两种:

  1. 在 AndroidManifes.xml 中 ,找到声明 Activity 的位置,在 Actvity XML 属性 android:launchMode="standard",其他模式(singleTop,singleTask,singleInstance) 声明。
  2. 在代码中跳转 Activity 时,利用 Intent 指定 Flag 标志位来使用启动模式。示例代码如下:
Intent intent = new Intent(this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//Flag
startActivity(intent);

setFlags方法说明

//使用一个新的Task来启动Activity,但每个Activity都将在一个新的Task中。
Intent.FLAG_ACTIVITY_NEW_TASK   
//使用singleTop模式来启动一个Activity。  
Intent.FLAG_ACTIVITY_SINGLE_TOP  
//使用singleTask模式来启动一个Activity。
Intent.FLAG_ACTIVITY_CLEAR_TOP
//使用singleTask模式来启动一个Activity,使用这种方式启动Activity,当Activity启动其他Activity的时候,该Activity会被销毁,不入栈。  
Intent.FLAG_ACTIVITY_NO_HISTORY
//方式无法指定 SingleInstance 模式,SingleInstances 只能在 AndroidManifest.xml 中声明。
Intent.setFlags
常见使用场景

这里是一些在开发中常见的业务场景页面使用的页面启动模式:

Android 四大组件之Activity

结语

作为Android的四大组件之一,并且也是项目开发过程中最常用到的,小伙伴们要深刻理解,并把它灵活的运用到项目中,当然这些也是面试中会问到的最基础问题。

PS:如果还有未看懂的小伙伴,欢迎加入我们的QQ技术交流群:892271582,里面有各种大神回答小伙伴们遇到的问题哦~

Android 四大组件之Activity

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
待兔 待兔
5年前
Android Activity生命周期,启动模式,启动过程详解
前言接触过Android开发的同学都知道Activity,Activity作为Android四大组件之一,使用频率高。简单来说Activity提供了一个显示界面,让用户进行各种操作,本文主要分为以下三个部分:Activity的生命周期,启动模式,以及Activity的工作过程。文中大部分篇幅来自《Android开发艺术探索》一书,尽管想多以流程或图
刘望舒 刘望舒
4年前
Android深入理解Context(二)Activity和Service的Context创建过程
Android框架层Android深入理解Contextcategories:Android框架层本文首发于微信公众号「刘望舒」前言上一篇文章我们学习了Context关联类和ApplicationContext的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程。需要注意的是,本篇的知识点会和深入理解四大组件系列的
刘望舒 刘望舒
4年前
Android深入四大组件(七)Android8.0 根Activity启动过程(后篇)
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言在几个月前我写了和这两篇文章,它们都是基于Android7.0,当我开始阅读Android8.0源码时发现应用程序(根Activity)启动过程照Android7.0有了一些变化,因此又写下了本篇文章,本篇文章照此前的文章不仅
刘望舒 刘望舒
4年前
Android深入四大组件(一)应用程序启动过程(前篇)
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「后厂技术官」前言在此前的文章中,我讲过了Android系统启动流程和Android应用进程启动过程,这一篇顺理成章来学习Android7.0的应用程序的启动过程。分析应用程序的启动过程其实就是分析根Activity的启动过程。<!more1
刘望舒 刘望舒
4年前
Android深入四大组件(六)Android8.0 根Activity启动过程(前篇)
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言在几个月前我写了和这两篇文章,它们都是基于Android7.0,当我开始阅读Android8.0源码时发现应用程序(根Activity)启动过程照Android7.0有了一些变化,因此又写下了本篇文章,本篇文章照此前的文章不仅
刘望舒 刘望舒
4年前
Android深入四大组件(五)Content Provider的启动过程
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言ContentProvider做为四大组件之一,通常情况下并没有其他的组件使用频繁,但这不能作为我们不去深入学习它的理由。关于ContentProvider一篇文章是写不完的,这一篇文章先来介绍它的启动过程。<!more1.q
刘望舒 刘望舒
4年前
Android深入四大组件(二)Service的启动过程
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言此前我用较长的篇幅来介绍Android应用程序的启动过程(根Activity的启动过程),这一篇我们接着来分析Service的启动过程。建议阅读此篇文章前,请先阅读和这两篇文章。<!more1.ContextImpl到Activi
Stella981 Stella981
4年前
Android 面试常问七道题
1Android的四大组件以及作用Activity:Activity是Android程序与用户交互的窗口,是Android构造块中最基本的一种,它需要为保持各界面的状态,做很多持久化的事情,妥善管理生命周期以及一些跳转逻辑。service:后台服务于Activity,封装有一个完整的功能逻辑实现,接受上层指令,完成相关的动作,