官术网_书友最值得收藏!

3.1 什么是ViewModel

按照官方描述,ViewModel類旨在以注重生命周期的方式存儲和管理界面相關(guān)的數(shù)據(jù)。ViewModel類可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后讓數(shù)據(jù)繼續(xù)留存。

上面的描述怎么理解呢?這里通過上一章遺留的問題來說明。在上一章中使用Lifecycle實現(xiàn)了廣告引導(dǎo)頁的需求,即用戶打開App進入引導(dǎo)頁面,倒計5秒后進入主頁面,正常操作下運行日志如圖3-1所示。

034-1

圖3-1 正常操作下的運行日志

如果在廣告剩余2秒的時候?qū)⑹謾C屏幕旋轉(zhuǎn),那么打印日志如圖3-2所示。

034-2

圖3-2 廣告剩余2秒旋轉(zhuǎn)屏幕日志

通過圖3-2可以發(fā)現(xiàn),屏幕旋轉(zhuǎn)后,原有計時停止后又重新開始了。出現(xiàn)這個問題的原因是當(dāng)屏幕旋轉(zhuǎn)時Activity被銷毀后又重新創(chuàng)建了。

注意

屏幕旋轉(zhuǎn)時,生命周期的變化取決于configChanges屬性,這里未配置config-Changes的屬性,所以屏幕由豎屏切換為橫屏?xí)r,會重新執(zhí)行每個生命周期方法。讀者可自行查閱configChanges的其他屬性值。

這種結(jié)果用戶肯定是不能接受的,因為旋轉(zhuǎn)屏幕操作導(dǎo)致用戶需要重復(fù)觀看廣告。這個問題一般如何處理呢?一種方式是通過修改configChanges屬性使得App在旋轉(zhuǎn)的時候不被銷毀,但因為有其他業(yè)務(wù)邏輯限制,所以這里不考慮。另一種常用的方式是通過重寫onSaveInstanceState方法在Activity被銷毀的時候?qū)?dāng)前計時的節(jié)點存儲起來,重新開始計時的時候從上次計時的節(jié)點開始計時。

在使用這種方式處理之前,首先需要修改上一章中AdvertisingManage的代碼計時器,將計時的起止時間修改為傳參的形式,示例代碼如下:

class AdvertisingManage(millisInFuture: Long = 5000) : LifecycleObserver
{         ...
        //定時器
    private var countDownTimer: CountDownTimer? = object : CountDownTimer(millisInFuture, 1000) {
    ...
}

這樣修改后,每次計時都會將當(dāng)前的計時記錄下來,便于下一次使用。示例代碼如下:

//計時的時長,默認(rèn)值5秒
var millisInFuture: Long = 5000
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    val advertisingManage = AdvertisingManage(millisInFuture)
    ...
    advertisingManage.advertisingManageListener =
        object : AdvertisingManage.AdvertisingManageListener {
            override fun timing(second: Int) {
                tvAdvertisingTime.text = "廣告剩余$second秒"
                millisInFuture = second.toLong() * 1000
            }
        .....
}

接著在Activity中重寫onSaveInstanceState方法,記錄Activity銷毀時計時的節(jié)點。在第二次創(chuàng)建AdvertisingManage實例的時候?qū)⑦€需要計時的時間傳給Advertising-Manage類。示例代碼如下:

//計時的時長,默認(rèn)值5秒
var millisInFuture: Long = 5000
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    savedInstanceState?.let {
        millisInFuture = it.getLong(KEY_MILLISINFUTURE)
    }
    val advertisingManage = AdvertisingManage(millisInFuture)
    ...
}
...
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putLong(KEY_MILLISINFUTURE, millisInFuture)
}
companion object {
    //key計時的開始時間
    const val KEY_MILLISINFUTURE = "keyMillsimfuture"
}

修改上述代碼之后,進行與前面相同的操作——廣告剩余2秒時將手機屏幕旋轉(zhuǎn)。打印日志如圖3-3所示。

036-1

圖3-3 廣告剩余2秒時旋轉(zhuǎn)屏幕的日志

通過打印的日志可以看到,在2秒時停止計時,屏幕旋轉(zhuǎn)后從1s開始計時,符合預(yù)期效果。上面是通過onSaveInstanceState方法來解決屏幕旋轉(zhuǎn)導(dǎo)致廣告重新計時這一問題的。那么是否有更優(yōu)雅的解決方案呢?

主站蜘蛛池模板: 五常市| 敦煌市| 阿勒泰市| 宁化县| 防城港市| 应用必备| 兰考县| 汨罗市| 晴隆县| 五峰| 沛县| 扬中市| 南城县| 沅陵县| 怀化市| 武乡县| 河东区| 金平| 定兴县| 沧源| 遵义市| 清远市| 荆门市| 周宁县| 朔州市| 安仁县| 安图县| 临潭县| 天长市| 荃湾区| 侯马市| 许昌市| 赤城县| 凤台县| 柏乡县| 唐河县| 云南省| 邮箱| 乐安县| 讷河市| 汝南县|