Android5:活动生命周期
创建项目Stopwatch

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center_horizontal"tools:context=".MainActivity"><Chronometerandroid:id="@+id/stopwatch"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="56sp" /><Buttonandroid:id="@+id/start_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/start" /><Buttonandroid:id="@+id/pause_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/pause" /><Buttonandroid:id="@+id/reset_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/reset" />
</LinearLayout>
strings.xml
<resources><string name="app_name">Stopwatch</string><string name="start">Start</string><string name="pause">Pause</string><string name="reset">Reset</string>
</resources>
MainActivity.kt
package com.demo.stopwatchimport androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.SystemClock
import android.widget.Button
import android.widget.Chronometerclass MainActivity : AppCompatActivity() {lateinit var stopwatch: Chronometer //The stopwatchvar running = false //Is the stopwatch running?var offset: Long = 0 //The base offset for the stopwatchoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)//Get a reference to the stopwatchstopwatch = findViewById<Chronometer>(R.id.stopwatch)//The start button starts the stopwatch if it's not runningval startButton = findViewById<Button>(R.id.start_button)startButton.setOnClickListener {if (!running) {setBaseTime()stopwatch.start()running = true}}//The pause button pauses the stopwatch if it’s runningval pauseButton = findViewById<Button>(R.id.pause_button)pauseButton.setOnClickListener {if (running) {saveOffset()stopwatch.stop()running = false}}//The reset button sets the offset and stopwatch to 0val resetButton = findViewById<Button>(R.id.reset_button)resetButton.setOnClickListener {offset = 0setBaseTime()}}//Update the stopwatch base time, allowing for any offsetfun setBaseTime() {stopwatch.base = SystemClock.elapsedRealtime() - offset}//Record the offsetfun saveOffset() {offset = SystemClock.elapsedRealtime() - stopwatch.base}
}
运行查看效果
代码说明
1.应用运行,MainActivity启动
初始化running和offset属性
2.调用MainActivity的onCreate方法
将activity_main.xml布局链接到活动,为stopwatch属性指定视图的一个引用
3.点击“Start”按键
秒表开始运行
4.点击“Pause”按钮
更新offset属性,并调用秒表的stop方法,running更新为false,秒表暂停
5.再次点击“Start”按钮
使用offset的值来调整stopwatch.base属性,调用start方法,更新running为true,表秒再次运行
6.点击“Reset”按钮
offset更新为0,stopwatch.base属性更新为SystemClock.elapsedRealtime()
但是这里有个问题,当旋转屏幕时,秒表会重置为0,并停止运行

旋转时发生了什么?
当屏幕方向有变化时,Android会撤销MainActivity,所以MainActivity的属性值会丢失
然后MainActivity会重启,它的所有属性都会重新初始化,并且再次运行onCreate()方法
活动从启动状态变成撤销状态时,会触发一些活动生命周期的方法:onCreate()和onDestroy()。这些是活动继承的生命周期方法,不过可以覆盖这些方法。
解决方案:使用Bundle
Bundle是一种保存键值对的对象。在活动撤销之前,Android允许你把键值对放在Bundle里面,然后在活动重建时,活动的新实例通过Bundle恢复属性值
活动撤销前都会调用onSaveInstanceState方法,所以这里需要覆盖onSaveInstanceState方法
活动重建时会调用onCreate()方法,这里通过检查savedInstanceState != null来判断是否需要恢复属性值
MainActivity.kt最终代码
package com.demo.stopwatchimport androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.SystemClock
import android.widget.Button
import android.widget.Chronometerclass MainActivity : AppCompatActivity() {lateinit var stopwatch: Chronometer //The stopwatchvar running = false //Is the stopwatch running?var offset: Long = 0 //The base offset for the stopwatch//Add key Strings for use with the Bundleval OFFSET_KEY = "offset"val RUNNING_KEY = "running"val BASE_KEY = "base"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)//Get a reference to the stopwatchstopwatch = findViewById<Chronometer>(R.id.stopwatch)//Restore the previous stateif (savedInstanceState != null) {offset = savedInstanceState.getLong(OFFSET_KEY)running = savedInstanceState.getBoolean(RUNNING_KEY)if (running) {stopwatch.base = savedInstanceState.getLong(BASE_KEY)stopwatch.start()} else setBaseTime()}//The start button starts the stopwatch if it's not runningval startButton = findViewById<Button>(R.id.start_button)startButton.setOnClickListener {if (!running) {setBaseTime()stopwatch.start()running = true}}//The pause button pauses the stopwatch if it’s runningval pauseButton = findViewById<Button>(R.id.pause_button)pauseButton.setOnClickListener {if (running) {saveOffset()stopwatch.stop()running = false}}//The reset button sets the offset and stopwatch to 0val resetButton = findViewById<Button>(R.id.reset_button)resetButton.setOnClickListener {offset = 0setBaseTime()}}override fun onPause() {super.onPause()if (running) {saveOffset()stopwatch.stop()}}override fun onResume() {super.onResume()if (running) {setBaseTime()stopwatch.start()offset = 0}}override fun onSaveInstanceState(savedInstanceState: Bundle) {savedInstanceState.putLong(OFFSET_KEY, offset)savedInstanceState.putBoolean(RUNNING_KEY, running)savedInstanceState.putLong(BASE_KEY, stopwatch.base)super.onSaveInstanceState(savedInstanceState)}//Update the stopwatch base time, allowing for any offsetfun setBaseTime() {stopwatch.base = SystemClock.elapsedRealtime() - offset}//Record the offsetfun saveOffset() {offset = SystemClock.elapsedRealtime() - stopwatch.base}
}
相关文章:
Android5:活动生命周期
创建项目Stopwatch activity_main.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayoutxmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_w…...
第2章 数据结构和算法概述
2.3线性结构和非线性结构 数据结构包括: 线性结构和非线性结构 2.3.1线性结构 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系线性结构有两种不同的存储结构,即顺序存储结构(数组)和链式存储结构(链表)。顺序存储的线性表称…...
WPF国际化的实现方法(WpfExtensions.Xaml)
https://blog.csdn.net/eyupaopao/article/details/120090431 resx资源文件实现 resx资源文件,实现的过程比第一种复杂,但resx文件本身编辑比较简单,维护起来比较方便。需要用到的框架:WpfExtensions.Xaml 为每种语言添加.resx资…...
【Linux】—— 进程程序替换
目录 序言 (一)替换原理 1、进程角度——见见猪跑 1️⃣ 认识 execl 函数 2、程序角度——看图理解 (二)替换函数 1、命名理解 2、函数理解 1️⃣execlp 2️⃣execv 3️⃣execvp 4️⃣execle 5️⃣execve 6️⃣execve…...
idea创建javaweb项目,jboss下没有web application
看看下图这个地方有没有web application...
广东灯具3D扫描抄数建模服务3D测绘出图纸三维逆向设计-CASAIM
灯具三维逆向建模是一种将实际物体转换为数字模型的过程。通过逆向工程技术,可以将现有的灯具进行3D扫描,然后利用专业的逆向设计软件将其转换为准确的三维模型。 以下是CASAIM实施灯具三维逆向建模的一般步骤图: 1. 扫描:三维扫…...
Nginx反向代理-负载均衡、webshell实践
目录 1.nginx反向代理-负载均衡 1)搭建web项目 2)修改 nginx.conf的配置 2.webshell 实践 1)异或操作绕过 2)取反绕过 3)php语法绕过 1.nginx反向代理-负载均衡 1)搭建web项目 首先通过SpringBoo…...
第六阶|见道明心的笔墨(上)从书法之美到生活之美——林曦老师的线上直播书法课
如果你有需要,可以找我的,我这边有老师的所有课程 如果你有需要,可以找我的,我这边有老师的所有课程...
nbcio-boot从3.0升级到3.1的出现用户管理与数据字典bug
升级后出现 系统管理里的用户管理出现下面问题 2023-08-17 09:44:38.902 [http-nio-8080-exec-4] [1;31mERROR[0;39m [36mo.jeecg.common.exception.JeecgBootExceptionHandler:69[0;39m - java.lang.String cannot be cast to java.lang.Long java.lang.ClassCastException:…...
Curson 编辑器
Curson 汉化与vacode一样 Curson 自带chat功能 1、快捷键ctrlk(代码中编辑) 2、快捷键ctrll 右侧打开窗口...
Shell编程学习之函数的应用
Shell编程中的函数:伪代码表示: function 函数名(){函数体}注意事项: 1.函数无参数; 2.函数无返回值类型; 3.function可以不写; 4.函数不被调用,就不会执行; 5.函数名不能使用…...
Fork/Join框架
是什么 Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 Fork: 把一个大任务切分为若干子任务并行的执行 Join: 合并这些子任务的执行结果,最后…...
LeetCode_字符串_中等_468.验证 IP 地址
目录 1.题目2.思路3.代码实现(Java) 1.题目 给定一个字符串 queryIP。如果是有效的 IPv4 地址,返回 “IPv4” ;如果是有效的 IPv6 地址,返回 “IPv6” ;如果不是上述类型的 IP 地址,返回 “Nei…...
ABAP Der Open SQL command is too big.
ABAP Der Open SQL command is too big. DBSQL_STMNT_TOO_LARGE CX_SY_OPEN_SQL_DB 应该是选择条件中 维护的条件值条数太多了...
QChart类用来 管理 图表的:数据序列(series)、图例(legend)和坐标轴(axis)
QChart类用来 管理 图表的:数据序列(series)、图例(legend)和坐标轴(axis) 1、数据序列类 继承关系 2、坐标轴类 的继承关系 3、图例类 什么是图例? 图例:是集中于地图…...
Servlet+JDBC实战开发书店项目讲解第10篇:在线客服功能实现
在线客服功能实现 实现思路 要实现在线客服功能,您可以考虑以下步骤: 创建一个用于存储客户消息和回复的数据库表。您可以使用JDBC连接到数据库,并使用SQL语句创建表格。 在您的Servlet中,创建一个用于处理客户消息和回复的POS…...
CVE-2023-21292 AMS框架层高危漏洞分析
文章目录 前言漏洞细节故事起源漏洞利用漏洞修复 总结 前言 本周在分析 Google 官方发布的 Android 2023 年8 月安全公告 涉及的漏洞补丁的时候,遇到一个有意思的漏洞:CVE-2023-21292。 之所以说它有意思是因为这个漏洞早在去年年底就在某平台上被国外…...
cuda、cuDNN、深度学习框架、pytorch、tentsorflow、keras这些概念之间的关系
当讨论CUDA、cuDNN、深度学习框架、pytorch、tensorflow、keras这些概念的时候,我们讨论的是与GPU加速深度学习相关的技术和工具。 CUDA(Compute Unified Device Architecture): CUDA是由NVIDIA开发的一种并行计算平台和编程模型&…...
第二讲:BeanFactory的实现
BeanFactory的实现 1. 环境准备2. 初始化DefaultListableBeanFactory3. 手动注册BeanDefinition4. 手动添加后置处理器5. 获取被依赖注入的Bean对象6. 让所有的单例bean初始化时加载7. 总结 Spring 的发展历史较为悠久,因此很多资料还在讲解它较旧的实现,…...
vue2+Spring Boot2.7 大文件分片上传
之前我们文章 手把手带大家实现 vue2Spring Boot2.7 文件上传功能 将了上传文件 但如果文件很大 就不太好处理了 按正常情况甚至因为超量而报错 这里 我弄了个足够大的文件 我们先搭建 Spring Boot2.7 环境 首先 application.yml 代码编写如下 server:port: 80 upload:path:…...
AI Agent在智能风控中的实战:多智能体欺诈检测与预警
AI Agent在智能风控中的实战:多智能体欺诈检测与预警 你有没有过明明是正常交易却被银行冻结账户的糟糕体验?或是听说过某电商平台上线新活动首日就被黑产团伙薅走数千万补贴的新闻?随着黑产欺诈向团伙化、专业化、动态化演进,传统依赖规则引擎、单模型机器学习的风控体系已…...
30岁裸辞后,我用两个月拿下AI应用认证,现在OFFER选择困难症犯了
30岁裸辞那天,我最怕的不是没收入,而是突然发现:过去积累的经验,正在被AI重新定价。以前会写方案、做表格、跟项目,算是职场硬通货;到了2026年,招聘JD里开始频繁出现AI工具应用、智能工作流、Pr…...
别再只测accuracy!DeepSeek集成测试必须监控的5个隐性指标(P99首token延迟、context bleed率、tool-call schema漂移)
更多请点击: https://intelliparadigm.com 第一章:DeepSeek集成测试的核心范式演进 DeepSeek大模型的工程化落地对集成测试提出了全新挑战:传统基于接口响应码与字段校验的测试范式已难以覆盖语义一致性、推理链鲁棒性、上下文敏感度等高阶质…...
开源 AI Agent Harness Engineering 框架全览:LangChain, AutoGPT, CrewAI 孰优孰劣?
开源 AI Agent Harness Engineering 框架全览:LangChain, AutoGPT, CrewAI 孰优孰劣? 关键词 AI Agent Harness Engineering、大语言模型编排(LLM Orchestration)、LangChain、AutoGPT、CrewAI、工具调用(Tool Calling)、多Agent协作、自主任务规划 摘要 随着大语言模型…...
Vue2-Verify:解决前端验证码安全性与用户体验平衡问题的技术方案实现
Vue2-Verify:解决前端验证码安全性与用户体验平衡问题的技术方案实现 【免费下载链接】vue2-verify vue的验证码插件 项目地址: https://gitcode.com/gh_mirrors/vu/vue2-verify 在当今Web应用开发中,验证码作为防止自动化攻击的关键安全组件&…...
3分钟告别英文恐惧:Android Studio中文界面轻松切换指南
3分钟告别英文恐惧:Android Studio中文界面轻松切换指南 【免费下载链接】AndroidStudioChineseLanguagePack AndroidStudio中文插件(官方修改版本) 项目地址: https://gitcode.com/gh_mirrors/an/AndroidStudioChineseLanguagePack 你是否曾经因…...
AWS DevOps Agent 完全指南
AWS DevOps Agent 是 AWS 推出的前沿 AI 运维代理,自主调查和解决事件、持续预防故障、提升系统可靠性。本文档覆盖从原理到实战的全生命周期管理。 一、定位与价值 一句话定义 AWS DevOps Agent = AI 驱动的 SRE 队友,724 自主调查告警、定位根因、生成修复方案、预防未来…...
关于内卷,几个值得深想的洞察
首先声明:这篇不劝躺平,也不教内卷——只是想说清楚,你到底在一个什么样的游戏里。 你以为内卷是“资源不足”,其实是“分配方式” 很多人对内卷有个本质上的认知错误:以为内卷是因为资源不够,大家为了抢资…...
C++的单例模式及其作用
什么是单例模式?无论是在面向对象编程还是软件架构中,单例模式都扮演着至关重要的角色。它不仅能够确保一个类只有一个实例存在,还能够提供全局访问点,使得我们可以方便地在程序的任何地方使用该实例。但有几个设计模式并非解决抽…...
在github上快速接入taotoken大模型api的python调用教程
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在GitHub上快速接入Taotoken大模型API的Python调用教程 对于希望快速集成大模型能力的开发者而言,找到一个统一、便捷的…...
