前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Android编程权威指南》之Activity的生命周期篇

《Android编程权威指南》之Activity的生命周期篇

作者头像
用户8928967
发布2021-08-20 17:01:42
6100
发布2021-08-20 17:01:42
举报
文章被收录于专栏:用户8928967的专栏

本章讲述 Activity 生命周期、状态以及状态切换时系统调用的方法。

activity状态图解

activity的状态( 某些场景下,暂停状态的activity可能会部分或完全可见)

  • Nonexistent 表示 activity 不存在了,看不见了,它没有在内存里,或者已经被销毁了,也没有关联的视图供用户查看或与之交互。(发生在点击了后腿按钮)
  • Stopped 表示 activity 在内存中具有实例,但其视图在屏幕上不可见。(发生在启动了另外的全屏 activity,或者点击了手机的主页按钮)
  • Paused 表示 activity 在前台不能与用户交互但视图可见或部分可见。(比如说跳出一个对话框)
  • Resumed 表示在内存中,完全可见且在前台的 activity。在任何给定时间,整个系统中只有一个活动可以处于 resumed 状态。这意味着,如果一项活动进入 resumed 状态,则另一项 activity 可能会退出 resumed 状态。

「Activity 类会提供许多回调,这些回调会让 Activity 知晓某个状态已经更改。」

通常,通过覆盖 onCreate(Bundle) 方法,activity 可以预处理以下 UI 相关工作:

  • 实例化组件并将它们放置在屏幕上(调用setContentView(int)方法);
  • 引用已实例化的组件;
  • 为组件设置监听器以处理用户交互;
  • 访问外部模型数据。

日志跟踪理解 activity 生命周期

介绍的 android.util.Log 类打印日志,在上一章 MainActivity.kt 的上方加上日志 TAG 定义,然后,在 onCreate()、onStart()、onResume()、onPause()、onStop()、onDestroy() 生命周期回调方法中分别打印日志。

代码语言:javascript
复制
private const val TAG = "MainActivity"

class MainActivity : AppCompatActivity() {
      ...
      override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart() called")
    }
    ...
}

启动 app 日志:

启动

点击 Home 键日志:

home

重新进入 app 日志:

resume

旋转 app 日志:

旋转

退出 app 日志:

退出

设备配置与 Activity 生命周期

旋转设备会改变设备配置(device configuration)。设备配置实际是指屏幕方向、屏幕像素密度、屏幕尺寸、键盘类型、语言等。

在运行时配置变更(runtime configuration change)发生时,可能会有更合适的资源来匹配新的设备配置。于是,Android销毁当前activity,为新配置寻找最佳资源,然后创建新实例使用这些资源。(在demo中,再创建了一个layout目录,并加了后缀-land,res/layout-land,于是结果是设备处于水平方向时,Android会找到并使用res/layout-land目录下的布局资源)

Android的配置修饰符列表及其代表的设备配置信息网址:http://developer.android.com/guide/topics/resources/providing-resources.html

UI 更新和多窗口模式

Android 7.0 之前,通常使用 onResume() 和 onPause() 来启动或者停止任何与 UI 相关的正在进行的更新(动画和刷新数据)。Android 7.0 之后,有了多窗口模式,已经暂停的 activity 也是可见的状态,我们是希望已经暂停的 activitiy 也表现的像正常活动一样。比如说看视频的时候,不过我们可以在将恢复播放和暂停的播放移至 onStart() 和 onStop() 中,这样就能满足需求了。

再探 activity 生命周期

protected void onSaveInstanceState(Bundle outState)【该方法通常在 onStop() 方法之前由系统调用,除非用户按后退键。(记住,按后退键就是告诉 Android,activity 用完了。随后,该 activity 就完全从内存中被抹掉,自然,也就没有必要为重建保存数据了。)】【 Bundle 是存储字符串键与限定类型值之间映射关系(键-值对)的一种结构】

所以,可通过覆盖 onSaveInstanceState(Bundle) 方法,将一些数据保存在 bundle 中,然后在 onCreate(Bundle) 方法中取回这些数据,解决旋转问题。

注意,在 Bundle 中存储和恢复的数据类型只能是基本类型(primitive type)以及可以实现 Serializable 或 Parcelable 接口的对象。在 Bundle 中保存定制类对象不是个好主意,因为你取回的对象可能已经没用了。比较好的做法是,通过其他方式保存定制类对象,而在Bundle中保存标识对象的基本类型数据。

完整activity生命周期

深入学习:activity 内存清理现状

低内存状态下,Android直接从内存清除整个应用进程,连带应用的所有activity。目前,Android还做不到只销毁单个activity。

这里还介绍了使用Android手机中开发者设置,启用 Don’t keep activities

单击后退键后,系统总是会销毁当前的activity,相当于告诉系统“用户不再需要使用当前的activity”。

深入学习:日志记录的级别与方法

当然,打印日志也是有级别的,通常打错误日志才用 Log.e,默认是红色,打出来很显眼,可是平常一些信息什么的,最好不要打到这个级别了,很影响排除错误。

日志级别

关于日志打印:https://www.jianshu.com/p/de79bbf35a5b

挑战练习:禁止一题多答

  1. 定义问题是否已经回答过问题的 boolean 类型的数组
代码语言:javascript
复制
private var mQuestionsAnswered: BooleanArray? = BooleanArray(questionBank.size)
  1. 写个方法专门用来设置答题按钮状态
代码语言:javascript
复制
private fun setBtnEnabled(enabled: Boolean) {
        trueButton.isEnabled = enabled
        falseButton.isEnabled = enabled
    }
  1. 每一次检查问题答案的时候,立即将答题按钮状态置为 false,并将是否回答过问题的 boolean 数组当前位置的值设置为 true,因此在 checkAnswer 方法里面加上两句代码
代码语言:javascript
复制
private fun checkAnswer(userAnswer: Boolean) {
        ...
       setBtnEnabled(false)
       mQuestionsAnswered?.set(currentIndex, true)
    }
  1. 每一次翻页都要更新当前问题是否回答过的按钮状态,所以updateQuestion() 方法中添加代码
代码语言:javascript
复制
private fun updateQuestion() {
        ...
        setBtnEnabled(!mQuestionsAnswered?.get(currentIndex)!!)
    }
  1. 为了解决旋转问题,所以是否回答过问题的数组也要保持下来,定义一个KEY,再在 onSaveInstanceState() 保存数组
代码语言:javascript
复制
private const val KEY_QUESTION_ANSWERED = "answered"

override fun onSaveInstanceState(savedInstanceState: Bundle) {
        ...
        savedInstanceState.putBooleanArray(KEY_QUESTION_ANSWERED, mQuestionsAnswered)
}
  1. 最后当然也要在onCreate方法中得到刚刚保存的是否回答过问题的数组,解决旋转初始化值的问题
代码语言:javascript
复制
if (savedInstanceState != null) {
    currentIndex = savedInstanceState.getInt(KEY_INDEX, 0)
    mQuestionsAnswered = savedInstanceState.getBooleanArray(KEY_QUESTION_ANSWERED)
}

挑战练习:评分 (用户答完全部题后,显示一个toast消息,给出百分比形式的评分)

  1. 定义一个 Int 类型的数,记录回答正确答案的个数,初始化为 0
代码语言:javascript
复制
 private var mTrueAnswerCount = 0
  1. 每次点击了回答问题的按钮,检测答案的时候,检查正确了,就将mTrueAnswerCount ++
代码语言:javascript
复制
private fun checkAnswer(userAnswer: Boolean) {
        val correctAnswer = questionBank[currentIndex].answer
        val messageResId = if (userAnswer == correctAnswer) {
            mTrueAnswerCount++
            R.string.correct_toast
        } else {
            R.string.incorrect_toast
        }
        Toast.makeText(this, messageResId, Toast.LENGTH_SHORT).show()
        setBtnEnabled(false)
        mQuestionsAnswered?.set(currentIndex, true)
        getScoreResult()
    }
  1. 写个得到评分的方法,一直在想,什么时候会答完题,因为可以跳着答题的嘛,恰好答完所有就跳出提示,所以我的处理是在 checkAnswer()方法的最后,都会调用一下得到评分结果的方法,而在 getScoreResult() 方法里面判断一下当前是否答完了所有题,没有不作任何处理,答完了就做计算弹出当前评分的百分比
代码语言:javascript
复制
private fun getScoreResult() {
        var isAllAnswered = true
        for (i in questionBank.indices) {
            if (!mQuestionsAnswered?.get(i)!!) {
                isAllAnswered = false
                return
            }
        }
        if (isAllAnswered) {
            Toast.makeText(
                this,
                "${mTrueAnswerCount * 100 / questionBank.size} %",
                Toast.LENGTH_LONG
            ).show()
        }
    }
  1. 最后一个旋转问题,当然又是定义一个key,保存当前回答正确的问题数喽
代码语言:javascript
复制
private const val KEY_TRUE_ANSWER_COUNT = "true_answer_count"

mTrueAnswerCount = savedInstanceState.getInt(KEY_TRUE_ANSWER_COUNT)

savedInstanceState.putInt(KEY_TRUE_ANSWER_COUNT, mTrueAnswerCount)

OK!完毕!ヾ(◍°∇°◍)ノ゙

上一篇 ——《Android编程权威指南》之Android与MVC篇

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 妮K妮K妮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 日志跟踪理解 activity 生命周期
  • 设备配置与 Activity 生命周期
  • UI 更新和多窗口模式
  • 再探 activity 生命周期
  • 深入学习:activity 内存清理现状
  • 深入学习:日志记录的级别与方法
  • 挑战练习:禁止一题多答
  • 挑战练习:评分 (用户答完全部题后,显示一个toast消息,给出百分比形式的评分)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档