<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # Lifecycle ## 解決問題: * activity的生命周期內有大量管理組件的代碼,難以維護。 * 無法保證組件會在 Activity/Fragment停止后不執行啟動 ## 實現 LifecycleOwner(如Activity)在生命周期狀態改變時(也就是生命周期方法執行時),遍歷觀察者,獲取每個觀察者的方法上的注解。 # LifeData **LiveData使得 數據的更新 能以觀察者模式 被observer感知,且此感知只發生在 LifecycleOwner的活躍生命周期狀態**。 ## 基本用法 1. 創建LiveData實例,指定源數據類型 2. 創建Observer實例,實現onChanged()方法,用于接收源數據變化并刷新UI 3. LiveData實例使用observe()方法添加觀察者,并傳入LifecycleOwner 4. LiveData實例使用setValue()/postValue()更新源數據 (子線程要postValue()) ## LiveData與MutableLiveData區別 1. MutableLiveData的父類是LiveData 2. LiveData在實體類里可以通知指定某個字段的數據更新. 3. MutableLiveData則是完全是整個實體類或者數據類型變化后才通知.不會細節到某個字段 4. LiveData不可變,MutableLiveData是可變的 ## 源碼分析(觀察者模式) LiveData原理是觀察者模式,下面就先從LiveData.observe()方法看起: ~~~ //key 觀察者 value 包裝的LifecycleOwner private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>(); ~~~ ## 事件推送,解決防止事件丟失 投遞事件時,如果判斷Lifecycle是否激活,如果NO,則把數據暫存起來 ## 解決數據倒灌 對于這個問題,總結一下發生的核心原因。對于LiveData,其初始的version是-1,當我們調用了其setValue或者postValue,其vesion會+1;對于每一個觀察者的封裝ObserverWrapper,其初始version也為-1,也就是說,每一個新注冊的觀察者,其version為-1;當LiveData設置這個ObserverWrapper的時候,如果LiveData的version大于ObserverWrapper的version,LiveData就會強制把當前value推送給Observer。 那么能不能從**Map容器mObservers中取到LifecycleBoundObserver,然后再更改version呢**?答案是肯定的,通過查看SafeIterableMap的源碼我們發現有一個protected的get方法。因此,在調用observe的時候,我們可以通過反射拿到LifecycleBoundObserver,再把LifecycleBoundObserver的version設置成和LiveData一致即可。 # ViewModel ## 特點 ### 生命周期長于Activity ViewModel最重要的特點是 生命周期長于Activity。來看下官網的一張圖: 看到在因屏幕旋轉而重新創建Activity后,ViewModel對象依然會保留。 只有Activity真正Finish的時ViewModel才會被清除。 也就是說,因系統配置變更Activity銷毀重建,ViewModel對象會保留并關聯到新的Activity。而Activity的正常銷毀(系統不會重建Activity)時,ViewModel對象是會清除的。 那么很自然的,因系統配置變更Activity銷毀重建,ViewModel內部存儲的數據 就可供重新創建的Activity實例使用了。這就解決了第一個問題。 ### 不持有UI層引用 我們知道,在MVP的Presenter中需要持有IView接口來回調結果給界面。 而ViewModel是不需要持有UI層引用的,那結果怎么給到UI層呢?答案就是使用上一篇中介紹的基于觀察者模式的LiveData。 并且,ViewModel也不能持有UI層引用,因為ViewModel的生命周期更長。 所以,ViewModel不需要也不能 持有UI層引用,那么就避免了可能的內存泄漏,同時實現了解耦。這就解決了第二個問題。 ## 原理 ### ViewModelStore ``` ** * 用于存儲ViewModels. * ViewModelStore實例 必須要能 在系統配置改變后 依然存在。 */ public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.put(key, viewModel); if (oldViewModel != null) { oldViewModel.onCleared(); } } final ViewModel get(String key) { return mMap.get(key); } Set<String> keys() { return new HashSet<>(mMap.keySet()); } /** * 調用ViewModel的clear()方法,然后清除ViewModel * 如果ViewModelStore的擁有者(Activity/Fragment)銷毀后不會重建,那么就需要調用此方法 */ public final void clear() { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } } ``` ### 配置更改重建后ViewModel依然存在 * 如果存儲器是空,就先嘗試 從lastNonConfigurationInstance從獲取 * mLastNonConfigurationInstances是在Activity的attach方法中賦值 * ActivityThread 中的 ActivityClientRecord 是不受 activity 重建的影響,那么ActivityClientRecord中lastNonConfigurationInstances也不受影響 # MVVM ![](https://img.kancloud.cn/45/10/4510e5022d43b4c4c729a6bdaf70aba3_826x446.png) **MVVM各職責如下**: * Model模型:業務相關的數據(如網絡請求數據、本地數據庫數據等)及其對數據的處理 * View視圖:頁面視圖(Activity/Fragment),負責接收用戶輸入、發起數據請求及展示結果頁面 * ViewModel:M與V之間的橋梁,負責業務邏輯 **MVVM特點**: * View層接收用戶操作,并通過持有的ViewModel去處理業務邏輯,請求數據; * ViewModel層通過Model去獲取數據,然后Model又將最新的數據傳回ViewModel層,到這里,ViewModel與Presenter所做的事基本是一樣的。但是ViewModel不會也不能持有View層的引用,而是View層會通過觀察者模式監聽ViewModel層的數據變化,當有新數據時,View層能自動收到新數據并刷新界面。 #### UI驅動 vs 數據驅動 `MVP`中,`Presenter`中需要持有`View`層的引用,當數據變化時,需要主動調用`View`層對應的方法將數據傳過去并進行UI刷新,這種可以認為是UI驅動;而`MVVM`中,`ViewModel`并不會持有`View`層的引用,`View`層會監聽數據變化,當`ViewModel`中有數據更新時,`View`層能直接拿到新數據并完成UI更新,這種可以認為是數據驅動,顯然,`MVVM`相比于`MVP`來說更加解耦。 # MVI架構 本質就是`單向數據流動`+`狀態集中管理` (谷歌推薦的最佳實踐) ## 單向數據流動 新`UI State`主要分為以下幾步: 1. `ViewModel` 會存儲并公開`UI State`。`UI State`是經過`ViewModel`轉換的應用數據。 2. `UI`層會向`ViewModel`發送用戶事件通知。 3. `ViewModel`會處理用戶操作并更新`UI State`。 4. 更新后的狀態將反饋給`UI`以進行呈現。 5. 系統會對導致狀態更改的所有事件重復上述操作。 ![](https://img.kancloud.cn/63/ff/63ff5a87bc977af093511c58f7aad69b_1852x1656.png) ### 優勢 單向數據流動可以實現關注點分離原則,它可以將狀態變化來源位置、轉換位置以及最終使用位置進行分離。 這種分離可讓`UI`只發揮其名稱所表明的作用:通過觀察`UI State`變化來顯示頁面信息,并將用戶輸入傳遞給`ViewModel`以實現狀態刷新。 換句話說,單向數據流動有助于實現以下幾點: 1. 數據一致性。界面只有一個可信來源。 2. 可測試性。狀態來源是獨立的,因此可獨立于界面進行測試。 3. 可維護性。狀態的更改遵循明確定義的模式,即狀態更改是用戶事件及其數據拉取來源共同作用的結果。 ## UIState 集中管理 ### 缺點 * 不相關的數據類型:`UI`所需的某些狀態可能是完全相互獨立的。在此類情況下,將這些不同的狀態捆綁在一起的代價可能會超過其優勢,尤其是當其中某個狀態的更新頻率高于其他狀態的更新頻率時。 * `UiState diffing`:`UiState` 對象中的字段越多,數據流就越有可能因為其中一個字段被更新而發出。由于視圖沒有 `diffing` 機制來了解連續發出的數據流是否相同,因此每次發出都會導致視圖更新。當然,我們可以對 `LiveData` 或`Flow`使用 `distinctUntilChanged()` 等方法來實現局部刷新,從而解決這個問題 ### UI State實現局部刷新 下面我們就來看下`LiveData`怎么實現屬性監聽 ~~~kotlin //監聽一個屬性 fun <T, A> LiveData<T>.observeState( lifecycleOwner: LifecycleOwner, prop1: KProperty1<T, A>, action: (A) -> Unit ) { this.map { StateTuple1(prop1.get(it)) }.distinctUntilChanged().observe(lifecycleOwner) { (a) -> action.invoke(a) } } //監聽兩個屬性 fun <T, A, B> LiveData<T>.observeState( lifecycleOwner: LifecycleOwner, prop1: KProperty1<T, A>, prop2: KProperty1<T, B>, action: (A, B) -> Unit ) { this.map { StateTuple2(prop1.get(it), prop2.get(it)) }.distinctUntilChanged().observe(lifecycleOwner) { (a, b) -> action.invoke(a, b) } } internal data class StateTuple1<A>(val a: A) internal data class StateTuple2<A, B>(val a: A, val b: B) //更新State fun <T> MutableLiveData<T>.setState(reducer: T.() -> T) { this.value = this.value?.reducer() } ~~~ 1. 如上所示,主要是添加一個擴展方法,也是通過`distinctUntilChanged`來實現防抖 2. 如果需要監聽多個屬性,例如兩個屬性有其中一個變化了就觸發刷新,也支持傳入兩個屬性 3. 需要注意的是`LiveData`默認是不防抖的,這樣改造后就是防抖的了,所以傳入相同的值是不會回調的 4. 同時需要注意下承載`State`的數據類需要防混淆 # 參考資料 [Google 推薦使用 MVI 架構?卷起來了~](https://juejin.cn/post/7048980213811642382) [“終于懂了“系列:Jetpack AAC完整解析(一)Lifecycle 完全掌握!](https://blog.csdn.net/hfy8971613/article/details/109641527) [Android消息總線的演進之路:用LiveDataBus替代RxBus、EventBus](https://tech.meituan.com/2018/07/26/android-livedatabus.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看