在范例Dessert App中利用timer来观察更复杂的生命周期
专案中的class DessertTimer有一个startTime()与stopTimer()
class DessertTimer {
// The number of seconds counted since the timer started
var secondsCount = 0
private var handler = Handler()
private lateinit var runnable: Runnable
fun startTimer() {...}
fun stopTimer() {...}
}
藉由Runnable与Handler以後台程序执行startTime()时
执行时会log每秒印出 Timer is at : $secondsCount
在MainActivity宣告一个变数
private lateinit var dessertTimer : DessertTimer
并在onCreate()中实例化
dessertTimer = DessertTimer()
Activity生命周期
可以看出在activity显现前,就会呼叫onStart(),而activity不可见之後,会呼叫onStop()
在这二个地方加入startTimer()与stopTimer()
override fun onStart() {
super.onStart()
dessertTimer.startTimer()
Timber.i("onStart Called")
}
override fun onStop(){
super.onStop()
dessertTimer.stopTimer()
Timber.i("onStop Called")
}
按分享键时,会使activity进入onPause(),但并未onStop()
所以Timer()仍会继续
按Home键到桌面,此时app进入onStop(),再使用最近任务将app叫回
又会进入onStart(),Timer也继续执行
若将onStop()中的stopTimer()注解掉,且未完整结束/退出app
则app即使未显示於萤幕,Timer()也会持续在後台执行与使用系统资源
这是一种memory leak
若dessertTimer.startTimer()置於onCreate()执行
则app从後台回到前台时,Timer()不会执行,因爲onCreate()在 app被onDestroy()只会执行一次
本段的重点爲:若在生命周期中设置了某些可能会一直使用资源的程序
同时也要注意什麽时候该设置结束的程序
当一个app中有许多类似Timer()这样的程序须要注意何时结束时
可以使用lifecycle library
如上一段的例子,通常是activity在各个生命周期发生时,设置程序该做什麽,如startTimer(),stopTimer()
但使用lifecycle library则反过来,让Timer()自我监控当生命周期改变时,该做什麽
lifecycle library主要有三个部分
LifecycleOwner
interfaceLifecycleObserver
interface在此范例app中,DessertTimer就是Lifecycle observers
因此,让DessertTimer实作LifecycleObserver
interface
得以观察activity的生命周期而自动进行对应动作
class DessertTimer(lifecycle: Lifecycle) : LifecycleObserver {
...
}
改写的class DessertTimer包含二件事情
LifecycleObserver
interface再用lifecycle呼叫addObserver()将DessertTimer这个class加到观察者,并初始化
实例化DessertTimer的时候,Lifecycle owner(MainActivity)将传入本身的lifecycle
所以这个动作就连结了MainActivity与DessertTimer
init {
lifecycle.addObserver(this)
}
接着在对应生命周期发生时,所要执行的方法前加上annotation
@OnLifecycleEvent
并将对应的生命周期事件作爲参数传入
如图,属於activity的生命周期皆可以被观察
因此我们要在activity的生命周期
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startTimer() {...}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopTimer() {...}
MainActivity就是本app的Lifecycle owner
而MainActivity继承自上层的FragmentActivity已实作了LifecycleOwner
再来是将MainActivity自身的lifecycle状态(Lifecycle class)
传给DessertTimer的建构子
dessertTimer = DessertTimer(this.lifecycle) //this = 当前的MainActivity
至此就完成了DessertTimer对MainActivity的观察
当MainActivity的生命周期改变时
DessertTimer即会依照设置的annotation,执行对应的方法
所以原先MainActivity onStart(),onStop()中执行的startTimer()与stopTimer()都不需要了
执行app,检查timer print log的动作应皆相同
app不在当前画面,刚进入後台时,还不会呼叫onDestroy()
等待使用者随时可快速的返回app
但android管理所有资源,可能因爲app久未被使用或资源不够
而将已进入後台的app完全关闭
以下用adb模拟android关闭app的情况(android api版本须爲28以上)
开啓Terminal,输入adb,正常要看到Android Debug Bridge version X.XX.X
出现如图这样表示没找到adb执行程序
找自己的Android SDK Location爲 C:\Users\user\AppData\Local\Android\Sdk\
但实际上adb.exe在platform-tools资料夹内
所以路径是
C:\Users\user\AppData\Local\Android\Sdk\platform-tools
再依照第二步,将SDK路径加入系统变数中
进阶系统设定->环境变数->系统变数
执行adb,看到版本号了
执行app并累积一些金额
按Home,将app收到後台
开啓Terminal,输入adb shell am kill com.example.android.dessertclicker
此指令功能爲将後台的app强制结束
再将app调回前台显示,原本从後台回到前台
预期app的内容应该是与进後台前相同
但被强制结束的app,可以回到前台之後,内容都被清空了
app的生命周期也从onCreate()开始执行,timer从0开始
android系统会自动保存已设置ID之view的状态
尽量於app恢复执行时,显示之前的状态
但有些程序中的变数,android系统不认得
因此若须要保存的话,可用onSaveInstanceState()
包装起来
<<: 远端系列 - 1:什麽是本地数据库(local repository)、远端数据库(remote repository)?
昨天稍微谈到了一些有关警报的设计,然而,警报的发出与否,应是建立在我们观测到的一些系统的行为,例如说...
续 Day 12 今天的特别理论和抽象,所以懒得看就跳过吧! 系统模型和现实 (System Mo...
今天来处理昨天建立的 Category 商品类别模型 假如说商店有机会扩大经营的话,那商品类别势必会...
作用域(scoop)简单来说,就是变数的地盘,在地盘内,变数都有作用,出了地盘,变数就undefi...
思路: 我一开始看到这题,感觉他像可以用Greedy解法解的问题,然後又想他是III,所以他也可以用...