Android的Activity生命周期知识点总结,详情

一. Activity生命周期

    1.1 返回栈知识点

二. Activity状态

    2.1 启动状态

    2.2 运行状态

    2.3 暂停状态

    2.4 停止状态

    2.5 销毁状态

三. Activity生存期

    3.1 回调方法

    3.2 生存期

四. 体验Activity的生命周期

五. Activity被回收办法

引言:

掌握Activity的生命周期对Android开发来说非常重要,当我们深入理解Activity的生命周期之后,就可以写出更加连贯流畅的理序,并在如何合理管理应用资源方面发挥得游刃有余。我们的应用程序也将会拥有更好的用户体验。

.Activity生命周期

1.1返回栈:

我们知道,Android里的Activity可以层叠的,我们每启动一个新的Activity,就会覆盖在原来的Activity之上,然后点击Back按键,会销毁最上面的Activity,下面的一个Activity就会显示出来。

其实Android是使用任务(task)来管理Activity的,一个任务就是一组存放在栈里的Activity的集合,这个栈也被称作返回栈(back stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的Activity,它就会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个Activity时,处于栈顶的Activity就会出栈,前一个入栈的Activity就会重新处于栈顶的位置。

系统总是会显示处于栈顶的Activity给用户。

1:返回栈流程图

1.2 Activity状态

Activity有主要的四个状态,以及一个非常迅速的启动状态,下面我们来讲解他们的功能:

1.2.1启动状态(Starting)

启动状态就是内个非常迅速的状态,在Activity启动时会自动跳转到下一个状态,这也就是为什么很多的Activity介绍里只写了四个状态而没有介绍这个状态了。

1.2.2运行状态(Running)

当一个Activity位于返回栈的栈顶时,Activity就处于运行状态。系统最不愿意回收的就是处于运行状态的Activity,因为这会带来非常差的运行体验。

1.2.3暂停状态(Paused)

当一个Activity不再处于栈顶的位置,但仍然可见时,Activity就进入了暂停状态。你可能会觉得,既然Activity已经不在栈顶了,怎么会可见呢?这是因为并不是每一个Activity都会占满整个屏幕,比如对话框式的Activity只会占用中间屏幕的部分区域。处于暂停状态的Activity仍然是完全存活的,系统也不愿意回收这种Activity(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种Activity

1.2.4停止状态(Stopped):

当一个Activity 不再处于栈顶位置,并且完全不可见的时候,就进人了停止状态。系统仍然会为这种Activity保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的Activity有可能会被系统回收。

1.2.5销毁状态(Destroyed):

一个Activity 从返回栈中移除后就变成了销毁状态。系统最倾向于回收处于这种状态的Activity以保证手机的内存充足。

2 :状态关系图

1.3生存期

1.3.1回调方法

Activity类中定义了7个回调方法,其覆盖了Activity生命周期的每一个环节,下面我们来一个一个看这 些方法:

1.onCreate()——创建

这个方法我们已经看到过很多次了,在每个Activity 中都重写了这个方法,它会在Activity第一次被创建的时候调用。我们应该在这个方法中完成Activity的初始化操作,比如加载布局、绑定事件等。

2.onStart()——启动

这个方法在Activity由不可见变为可见的时候调用

3.onResume()——恢复

这个方法在Activity准备好和用户进行交互的时候调用。此时的Activity一定位于返回栈的栈顶,并且处于运行状态。

4.onPause()——停顿

这个方法在系统准备去启动或者恢复另一个Activity的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。

5.onStop()——暂停

这个方法在Activity完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新Activity是一个对话框式的Activity,那么onPause()方法会得到执行,而onstop()方法并不会执行。

6.onDestory()——销毁

这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。

7.onRestart——重启

这个方法在Activity由停止状态变为运行状态之前调用,也就是Activity被重新启动了。

1.3.2生存期

1.3.2.1完整生存期

完整生存期:Activity在onCreate()方法和onDestroy()方法之间所经历的就是完整生存期。一般情况下, 一个Activity会在onCreate()方法中完成各种初始化操作,而在onDestroy()方法中完成释放内存的操 作。

1.3.2.2可见生存期

ActivityonStart()方法和onStop()方法之间所经历的就是可见生存期。在可见生存期内,Activity对于用户总是可见的,即便有可能无法和用户进行交互。我们可以通过这两个方法合理地管理那些对用户可见的资源。比如在onStart()方法中,对资源进行加载,而onStop()方法中对资源进行释放,从而保证处于停止状态的Activity不会占用过多内存。

1.3.2.3前台生存期

ActivityonResume()方法和onPause()方法之间所经历的就是前台生存期。在前台生存期内, Actvity总是处于运行状态,此时的 Activity 是可以和用户进行交互的,我们平时看到和接触最多的就是这个状态下的Activity。

3.Activity生命周期

1.4体验Activity的生命周期

了解了Activity的生命周期之后,我们来写一个实例,通过实例来详细了解。

首先,我们新建一个EmptyActivity,名为NormalActivity,其布局起名为normal_layout;使用相同的方法创建DialogActivity,布局起名为dialog_layout

接下来,我们先编辑normal_layout.xml文件。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_ parent"

android:layout_height="match_ parent">

<Textview

android:Layout_width="match_parent"

android:layout_height="wrap_content

android:text="This is a normal activity"

/>

</LinearLayout>

在这里我们简单的定义了一个TextView,显示了一行文字"This is a normal activity"

接着我们编辑dialog_layout.xml文件,代码如下:

<LinearLayout xmlns:android-"http://schemas.android.com/apk/res/android

android:orientation"vertical"

android: Layout_width="match_parent"

android: layout_height="match_parent">

<Textview

android:layout_width="match_parent"

android: layout_height="wrap_content"

android:text="This is a dialog activity"

/>

</LinearLayout>

接下来我们修改AndroidManifest.xml的标签配件。

< activity
               android : name = ".DialogActivity"
               android : theme = "@style/Animation.Design.BottomSheetDialog" >
        </ activity >
< activity
               android : name = ".NormalActivity"
               android : exported = "false" />

这里注册了两个Activity,此时我们为什么使用了一个android:theme的属性?这里是给前面的Activity指定主题,这里的"@style/Animation.Design.BottomSheetDialog"则毫无疑问是让DialogActivity使用对话框的主题。现在,我们可以修改activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

         android:orientation="vertical"

         android:layout_width="match_parent"

         android:layout_height="wrap_content">

      <Button

             android:layout_width="match_parent"

             android:layout_height="wrap_content"

             android:id="@+id/startNormalActivity"

             android:text="Start NormalActivity"/>

         <Button

                android:layout_width="match_parent"

                android:layout_height="wrap_content"

                android:id="@+id/startDialogActivity"

                android:text="Start DialogActivity"/>

</LinearLayout>

这里我们添加两个按钮,一个用于启动NormalActivity,一个用于启动DialogActivity,修改代码:

import android.content.Intent;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

@Override

protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      Log.d(TAG, "onCreate");

      setContentView(R.layout.activity_main);

      findViewById(R.id.startNormalActivity).setOnClickListener(new

View.OnClickListener() {

            @Override

            public void onClick(View v) {

                   Intent intent = new Intent(MainActivity.this,

NormalActivity.class);

                     startActivity(intent);

                   }

             });

             findViewById(R.id.startDialogActivity).setOnClickListener(new

View.OnClickListener() {

                 @Override

                  public void onClick(View v) {

                         Intent intent = new Intent(MainActivity.this,

  DialogActivity.class);

                         startActivity(intent);

                 }

           });

  }

  @Override

  protected void onStart() {

          super.onStart();

          Log.d(TAG, "onStart");

  }

  @Override

  protected void onResume() {

         super.onResume();

         Log.d(TAG, "onResume");

  }

  @Override

  protected void onPause() {

         super.onPause();

         Log.d(TAG, "onPause");

  }

  @Override

  protected void onStop() {

         super.onStop();

         Log.d(TAG, "onStop");

  }

  @Override

  protected void onDestroy() {

        super.onDestroy();

        Log.d(TAG, "onDestroy");

  }

}

现在,我们启动程序,并看一下logcat的效果。

4Main界面图

此时我们不对界面做任何操作,看log cat运行过程:

图5:MainLogCat打印日志

这里其实我们就会发现,在MainActivity第一次被创建时会依次执行onCreateonStartonResume方法。

然后点击第一个按钮NormalActivity,打开normal_layout界面:

图6:NormalActivity界面

此时的Logcat打印日志:

图7:NormalActivity的LogCat打印日志

由于此时NormalActivity已经把MainActivity完全遮挡住,所以onPauseonStop都会执行。然后按下Back按键返回MainActivity

这时候我们返回原来的界面,再看log cat打印日志:

图8:返回MainActivity时的打印日志

由于之前的MainActivity已经进入了停止状态,所以onRestart方法会得到执行,之后会依次执行

onRestartonResume方法,此时onCreate方法不会执行,因为MainActivity并没有重新创建。

点击第二个按钮,启动DialogActivity

此时的logcat:

图9:打开DialogActivity界面

可以看到,只有onPause的方法得到了执行,onStop没有得到执行,这是因为DialogActivity并没有完全遮挡住MainActivity,此时MainActivity只是进入暂停状态,并没有进入停止状态。

最后在MainActivity按下Back按键,退出程序,打印程序:

图10:结束界面

1.5Activity被回收办法

前面讲过,当一个Activity进入了停止状态,是有可能被系统回收的。我们可以假设一种情况:有一个ActivityA,我们在这个基础上启动了ActivityB,这时候A任务就陷入停止状态,这个时候由于系统的内存不足,系统将ActivityA回收掉了,然后用户按下Back按键返回ActivityA,正常情况下还是会显示ActivityA,这是并不会执行onRestart方法,而是会执行onCreate方法,因为A在这种情况下被重新创建一次。

但是偶尔我们还是回遇见一种情况,如果在A中可能会存在临时数据和状态,比如说A里有一个文本输入框,我们输入了一段数据;拿上面内个程序举例,此时我们打开了NormalActivity,这时MainActivity由于内存不足被回收掉,此时我们如果点击Back返回;此时如果内存不足的话,刚刚输入的文字就都没了,因为MainActivity被重建了。

这种情况是非常影响用户体验的,这时Activity里有一种回调方法我们就可以使用了——onSaveInstanceState(),这个方法可以保证在Activity被回收之前一定会被调用。

omSaveInstanceState()方法携带一个Bundle类的参数,Bundle提供一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存整型数据,以此类推。每个保存方法需传入两个参数,第一个参数是键,用于后面的Bundle中取值,第二个参数是真正要保存到内容。

@Override

protected void onSaveInstanceState(Bundle outState) {

      super.onSaveInstanceState(outState);

      String tempData = "Something you just typed";

      outState.putString("data_key", tempData);

}

数据已经保存下来了,那么我们在哪里恢复呢?我们一直使用的onCreate方法其实也有一个Bundle类型的参数。这个参数在一般情况下都是null。但是如果在Activity被系统回收之前,我们通过 onSaveInstanceState方法保存数据,这个参数就会带有之前的保存的数据,我们只需要通过相应的取值方法将数据去除,修改代码如下:

import android.os.Bundle;

import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

public class MyActivity extends AppCompatActivity {

      private static final String TAG = "MyActivity"; // 确保你有一个合适的TAG 

      super.onCreate(savedInstanceState);

      Log.d(TAG, "onCreate");

      setContentView(R.layout.activity_main);

      if (savedInstanceState != null) {

            String tempData = savedInstanceState.getString("data_key");

             Log.d(TAG, "tempData is " + tempData);

         }

     }  

}

取出值之后再做相应的恢复操作就可以了。

我们会发现在使用Bundle保存和取出数据的时候和使用Intent传递 也有类似的方法。这里Intent还可以结合Bundle一起用于传递数据。

首先我们可以把传递的数据都保存在Bundle对象中,然后再将Bundle对象存放在Intent里,到了目标的Activity之后,先从Intent中取出Bundle,再从Bundle中一一取出数据。

注:另外,当手机的屏幕旋转的时候,Activity也会有一个重建的过程,所以这时候,数据也可能发生丢失的情况。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/19341.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

frp-tool,客户端frp命令行工具

在日常开发和运维过程中&#xff0c;端口转发和配置管理是常见的需求。 如果有自己一台服务器&#xff0c;并且已经开放好端口&#xff0c;配置好token后&#xff0c;这个工具一定能帮到你。 今天给大家推荐一款非常好用的frpc命令行工具&#xff0c;它是一个用Python编写的命令…

netcore https配置

一、生成证书 1. 安装 OpenSSL 如果尚未安装 OpenSSL&#xff0c;可以通过以下命令安装&#xff1a;Ubuntu/Debian:sudo apt update sudo apt install openssl CentOS/RHEL:sudo yum install openssl 2. 生成私钥 使用以下命令生成私钥文件&#xff08;private.key&#xff09…

解锁ApplicationContext vs BeanFactory: 谁更具选择性?

目录 一、聚焦源码回顾 &#xff08;一&#xff09;源码分析和理解 &#xff08;二&#xff09;简短的回顾对比建议 二、ApplicationContext vs BeanFactory特性对比 &#xff08;一&#xff09;主要特性总结 &#xff08;二&#xff09;直接建议 三、案例简单说明 &am…

【大模型】DeepSeek 高级提示词技巧使用详解

目录 一、前言 二、DeepSeek 通用提示词技巧 2.1 DeepSeek 通用提示词技巧总结 三、DeepSeek 进阶使用技巧 3.1 DeepSeek一个特定角色的人设 3.1.1 为DeepSeek设置角色操作案例一 3.1.2 为DeepSeek设置角色操作案例二 3.2 DeepSeek开放人设升级 3.2.1 特殊的人设&#…

1-2 gitee创建远程仓库

如何创建远程仓库&#xff1f; 第一步点击加号&#xff0c;创建仓库 点击创建仓库给新创建的仓库命名即可 仓库创建成功即可

浏览器打开Axure RP模型

1&#xff0c;直接使用chrome打开&#xff0c;提示下载插件 2&#xff0c;需要做一些操作 打开原型文件&#xff0c;找到resources\chrome\axure-chrome-extension.crx文件&#xff0c;这就是我们需要的Chrome插件。 将axure-chrome-extension.crx文件后缀名改为axure-chrome…

Linux环境下安装mkcert

官网&#xff1a;https://github.com/FiloSottile/mkcert 选择对应的处理器的型号去下载对应的版本 ./mkcert-v1.4.4-linux-amd64 -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1命令解析 -key-file key.pem&#xff1a;指定输出的私钥文件名为key.pem。私钥…

【动态路由】系统web url整合系列【springcloud-gateway实现】【不改hosts文件版】组件一:多个Eureka路由过滤器

需求 实现URL web资源整合&#xff0c;实现使用一个web地址访问多个web资源 方案 本方案使用SpringCloud Gateway实现&#xff0c;不需要在hosts文件加添加域名映射&#xff08;也不需要定义一系列域名&#xff09;&#xff0c;通过url路径来将请求转发到不同的Web资源 如&…

【ubuntu24.04】 强制重启导致大模型的磁盘挂载出错

挂载NTFS文件系统出错 各种模型放在了这个机械硬盘上&#xff0c;虽然速度慢&#xff0c;但是好在容量大。大模型在工作&#xff0c;但是程序看起来有问题&#xff0c;导致系统卡死了&#xff0c;然后我重启了&#xff0c;然后报错&#xff1a;wrong fs type bad option &…

细说STM32F407单片机RTC入侵检测和时间戳的原理及使用方法

目录 一、入侵检测的功能 二、示例功能 三、项目设置 1、晶振、DEBUG、CodeGenerator、USART6、KEYLED 2、RTC &#xff08;1&#xff09;设置RTC的模式。 &#xff08;2&#xff09;General、Time、Date\Wake Up分组 &#xff08;3&#xff09;Tamper分组 1&#xff…

教程:使用 Vue 3 和 arco 实现表格合并

1. 功能概述 本教程将介绍如何使用 Vue 3 和 arco 组件库实现表格合并功能。具体来说&#xff0c;我们会根据表格数据中的某个字段&#xff08;如 type&#xff09;对表格的某一列&#xff08;如入库类型列&#xff09;进行合并&#xff0c;同时将质检说明列合并为一列。 2. …

位图(C语言版)

文章目录 位图模型基本操作实现代码运行结果 应用存储只有两种状态的数据排序并去重 位图 模型 位图是“位”的数组。 为什么需要构建一个专门的数据结构来表示位的数组&#xff1f;&#xff1a;因为计算机最小的寻址单位是字节&#xff0c;而不是位。 位图是一种内存紧凑的…

AI写代码工具时代:前端开发技能迭代的挑战与应对

近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术飞速发展&#xff0c;深刻地改变着各个行业&#xff0c;前端开发领域也不例外。AI技术不仅带来了新的开发模式&#xff0c;也显著加快了前端开发技能的迭代速度&#xff0c;给前端工程师带来了巨大的挑战。本文将深入…

文件上传功能(四)——项目集成

总说 过程参考黑马程序员SpringBoot3Vue3全套视频教程&#xff0c;springbootvue企业级全栈开发从基础、实战到面试一套通关_哔哩哔哩_bilibili 目录 总说 一、功能实现 1.1 Controller层 1.2 测试接口 一、功能实现 我们要将入门程序改为一个工具类 在utils目录下创建A…

使用 GPT-SoVITS 克隆声音,很详细

使用 GPT-SoVITS 克隆声音&#xff0c;很详细 一、前言二、下载三、启动四、克隆声音1、准备克隆音频2、分离人声伴奏3、音频分割4、语音降噪5、ASR工具6、语音文本校对标注工具7、训练模型8、微调训练9、推理 一、前言 最近对文本转语言很感兴趣&#xff0c;但对直接在网站上…

STM32+Proteus+DS18B20数码管仿真实验

1. 实验准备 硬件方面&#xff1a; 了解 STM32 单片机的基本原理和使用方法&#xff0c;本实验可选用常见的 STM32F103 系列。熟悉 DS18B20 温度传感器的工作原理和通信协议&#xff08;单总线协议&#xff09;。数码管可选用共阴极或共阳极数码管&#xff0c;用于显示温度值。…

【银河麒麟高级服务器操作系统】服务器卡死后恢复系统日志丢失-分析及处理全过程

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://document.kylinos.cn 服务器环境以及配置 【机型】 处理器&#xff…

【linux】在 Linux 上部署 DeepSeek-r1:32/70b:解决下载中断问题

【linux】在 Linux 上部署 DeepSeek-r1:32/70b:解决下载中断问题 【承接商业广告,如需商业合作请+v17740568442】 文章目录 【linux】在 Linux 上部署 DeepSeek-r1:32/70b:解决下载中断问题问题描述:解决方法方法一:手动中断并重启下载方法二:使用 Bash 脚本自动化下载在…

Java(api中常用类,包括Object类,Arrays类,String类,基本数据类型包装类)

目录 一.api 1.api介绍: 二.Object类 1.toString方法 2.equals方法 1.什么是equals方法 2.Object类向我们提供的equals方法 ​编辑 3.equals方法与""的区别 三.Arrays类 1.toString方法 2.sort方法 3.copyOf方法 4.fill方法 5.binarySearch方法 四.基…

物联网行业通识:从入门到深度解析

物联网行业通识&#xff1a;从入门到深度解析 &#xff08;图1&#xff1a;物联网生态示意图&#xff09; 一、引言&#xff1a;万物互联时代的到来 根据IDC最新预测&#xff0c;到2025年全球物联网设备连接数将突破410亿&#xff0c;市场规模达1.1万亿美元。物联网&#xff…