最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Android如何設(shè)計(jì)一個(gè)全局可調(diào)用的ViewModel對(duì)象

 更新時(shí)間:2023年05月17日 11:22:28   作者:TimeFine  
很多時(shí)候我們需要維護(hù)一個(gè)全局可用的ViewModel,因?yàn)檫@樣可以維護(hù)全局同一份數(shù)據(jù)源,且方便使用協(xié)程綁定App的生命周期,那如何設(shè)計(jì)全局可用的ViewModel對(duì)象,文中介紹的非常詳細(xì),需要的朋友可以參考下

一、思路

viewModel對(duì)象是存儲(chǔ)在ViewModelStore中的,那么如果我們創(chuàng)建一個(gè)全局使用的ViewModelStore并且在獲取viewModel對(duì)象的時(shí)候從它里面獲取就可以了。

viewModel是通過ViewModelProviderget方法獲取的,一般是ViewModelProvider(owner: ViewModelStoreOwner, factory: Factory).get(ViewModel::class.java)。

如何將ViewModelProviderViewModelStore關(guān)聯(lián)起來? 紐帶就是ViewModelStoreOwner, ViewModelStoreOwner是一個(gè)接口,需要實(shí)現(xiàn)getViewModelStore()方法,而該方法返回的就是ViewModelStore:

public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();   //返回一個(gè)ViewModelStore
}

讓某個(gè)類實(shí)現(xiàn)這個(gè)接口,重寫方法返回我們定義的ViewModelStore就可以了。

至于上面ViewModelProvider構(gòu)造方法的第二個(gè)參數(shù)Factory是什么呢?

源碼中提供了二種Factory,一種是NewInstanceFactory,一種是AndroidViewModelFactory,它們的主要區(qū)別是:

  • NewInstanceFactory創(chuàng)建ViewModel時(shí),會(huì)為每個(gè)Activity或Fragment創(chuàng)建一個(gè)新的ViewModel實(shí)例,這會(huì)導(dǎo)致ViewModel無法在應(yīng)用程序的不同部分共享數(shù)據(jù)。(ComponentActivity源碼getDefaultViewModelProviderFactory方法)

  • AndroidViewModelFactory可以訪問應(yīng)用程序的全局狀態(tài),并且ViewModel實(shí)例可以在整個(gè)應(yīng)用程序中是共享的。

根據(jù)我們的需求,需要用的是AndroidViewModelFactory。

二、具體實(shí)現(xiàn)

1、方式一:可以全局添加和獲取任意ViewModel

定義Application,Ktx.kt文件

import android.app.Application

lateinit var appContext: Application

fun setApplicationContext(context: Application) {
    appContext = context
}

定義全局可用的ViewModelOwner實(shí)現(xiàn)類

object ApplicationScopeViewModelProvider : ViewModelStoreOwner {

    private val eventViewModelStore: ViewModelStore = ViewModelStore()

    override fun getViewModelStore(): ViewModelStore {
        return eventViewModelStore
    }

    private val mApplicationProvider: ViewModelProvider by lazy {
        ViewModelProvider(
            ApplicationScopeViewModelProvider,
            ViewModelProvider.AndroidViewModelFactory.getInstance(appContext)
        )
    }

    fun <T : ViewModel> getApplicationScopeViewModel(modelClass: Class<T>): T {
        return mApplicationProvider.get(modelClass)
    }
}

定義一個(gè)ViewModel通過StateFlow定義發(fā)送和訂閱事件的方法

class EventViewModel : ViewModel() {

    private val mutableStateFlow = MutableStateFlow(0)

    fun postEvent(state: Int) {
        mutableStateFlow.value = state
    }

    fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = { _ -> }) {
        val eventScope = scope ?: viewModelScope
        eventScope.launch {
            mutableStateFlow.collect {
                method.invoke(it)
            }
        }
    }
}

定義一個(gè)調(diào)用的類

object FlowEvent {

    //發(fā)送事件
    fun postEvent(state: Int) {
        ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
            .postEvent(state)
    }

    //訂閱事件
    fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = { _ -> }) {
        ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
            .observeEvent(scope, method)
    }
}

測(cè)試代碼如下:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //打印協(xié)程名稱
        System.setProperty("kotlinx.coroutines.debug", "on")

        FlowEvent.observeEvent {
            printMsg("MainActivity observeEvent before :$it")
        }
        //修改值
        FlowEvent.postEvent(1)


        FlowEvent.observeEvent {
            printMsg("MainActivity observeEvent after :$it")
        }

    }

}

//日志
內(nèi)容:MainActivity observeEvent before :0 線程:main @coroutine#1
內(nèi)容:MainActivity observeEvent before :1 線程:main @coroutine#1
內(nèi)容:MainActivity observeEvent after :1 線程:main @coroutine#2

2、方式二:更方便在Activity和Fragment中調(diào)用

定義Application,讓BaseApplication實(shí)現(xiàn)ViewModelStoreOwner

//BaseApplication實(shí)現(xiàn)ViewModelStoreOwner接口
class BaseApplication : Application(), ViewModelStoreOwner {

    private lateinit var mAppViewModelStore: ViewModelStore
    private var mFactory: ViewModelProvider.Factory? = null

    override fun onCreate() {
        super.onCreate()
        //設(shè)置全局的上下文
        setApplicationContext(this)
        //創(chuàng)建ViewModelStore
        mAppViewModelStore = ViewModelStore()

    }

    override fun getViewModelStore(): ViewModelStore = mAppViewModelStore

    /**
     * 獲取一個(gè)全局的ViewModel
     */
    fun getAppViewModelProvider(): ViewModelProvider {
        return ViewModelProvider(this, this.getAppFactory())
    }

    private fun getAppFactory(): ViewModelProvider.Factory {
        if (mFactory == null) {
            mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(this)
        }
        return mFactory as ViewModelProvider.Factory
    }
}

Ktx.kt文件也有變化,如下

lateinit var appContext: Application

fun setApplicationContext(context: Application) {
    appContext = context
}

//定義擴(kuò)展方法
inline fun <reified VM : ViewModel> Fragment.getAppViewModel(): VM {
    (this.requireActivity().application as? BaseApplication).let {
        if (it == null) {
            throw NullPointerException("Application does not inherit from BaseApplication")
        } else {
            return it.getAppViewModelProvider().get(VM::class.java)
        }
    }
}

//定義擴(kuò)展方法
inline fun <reified VM : ViewModel> AppCompatActivity.getAppViewModel(): VM {
    (this.application as? BaseApplication).let {
        if (it == null) {
            throw NullPointerException("Application does not inherit from BaseApplication")
        } else {
            return it.getAppViewModelProvider().get(VM::class.java)
        }
    }
}

BaseActivityBaseFragment中調(diào)用上述擴(kuò)展方法

abstract class BaseActivity: AppCompatActivity() {

    //創(chuàng)建ViewModel對(duì)象
    val eventViewModel: EventViewModel by lazy { getAppViewModel() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }
}
abstract class BaseFragment: Fragment() {

    //創(chuàng)建ViewModel對(duì)象
    val eventViewModel: EventViewModel by lazy { getAppViewModel() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }
}

測(cè)試代碼

class MainActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //打印協(xié)程名稱
        System.setProperty("kotlinx.coroutines.debug", "on")

        eventViewModel.observeEvent {
            printMsg("MainActivity observeEvent :$it")
        }

        findViewById<AppCompatButton>(R.id.bt).setOnClickListener {
            //點(diǎn)擊按鈕修改值
            eventViewModel.postEvent(1)
            //跳轉(zhuǎn)到其他Activity
            Intent(this, TwoActivity::class.java).also { startActivity(it) }
        }
    }

}
class TwoActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_two)

        eventViewModel.observeEvent {
            printMsg("TwoActivity observeEvent :$it")
        }
    }
}

日志

內(nèi)容:MainActivity observeEvent :0 線程:main @coroutine#1
內(nèi)容:MainActivity observeEvent :1 線程:main @coroutine#1
內(nèi)容:TwoActivity observeEvent :1 線程:main @coroutine#2

以上就是詳解Android如何設(shè)計(jì)一個(gè)全局可調(diào)用的ViewModel對(duì)象的詳細(xì)內(nèi)容,更多關(guān)于Android ViewModel對(duì)象的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解android使用ItemDecoration 懸浮導(dǎo)航欄效果

    詳解android使用ItemDecoration 懸浮導(dǎo)航欄效果

    本篇文章主要介紹了Android 最流行的吸頂效果的實(shí)現(xiàn)及代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2017-01-01
  • Android ListView滑動(dòng)改變標(biāo)題欄背景漸變效果

    Android ListView滑動(dòng)改變標(biāo)題欄背景漸變效果

    這篇文章主要為大家詳細(xì)介紹了Android ListView滑動(dòng)改變標(biāo)題欄背景漸變效果,透明轉(zhuǎn)變成不透明,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Android電池電量監(jiān)聽的示例代碼

    Android電池電量監(jiān)聽的示例代碼

    本篇文章主要介紹了Android電池電量監(jiān)聽的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • Android利用滑動(dòng)菜單框架實(shí)現(xiàn)滑動(dòng)菜單效果

    Android利用滑動(dòng)菜單框架實(shí)現(xiàn)滑動(dòng)菜單效果

    這篇文章主要介紹了Android實(shí)現(xiàn)滑動(dòng)菜單特效之滑動(dòng)菜單框架完全解析,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • Android筆記之:App列表之下拉刷新的使用

    Android筆記之:App列表之下拉刷新的使用

    本篇文章介紹了,在Android中App列表之下拉刷新的使用。需要的朋友參考下
    2013-04-04
  • android里面屏蔽home鍵/禁止Home鍵或者隨你DIY

    android里面屏蔽home鍵/禁止Home鍵或者隨你DIY

    可以先禁止Home鍵,再在onKeyDown里處理按鍵值,點(diǎn)然后在擊Home鍵的時(shí)候就把程序關(guān)閉,或者隨你DIY等等,感覺你可以隨心所欲吧,再接再厲,希望本文可以幫助到你
    2013-01-01
  • Android?RxJava與Retrofit結(jié)合使用詳解

    Android?RxJava與Retrofit結(jié)合使用詳解

    RxJava和Retrofit的結(jié)合使用估計(jì)已經(jīng)相當(dāng)普遍了,自己工作中也是一直都在使用。在使用的過程中我們都會(huì)對(duì)其進(jìn)行封裝使用,GitHub上也有很多封裝好的項(xiàng)目可以直接拿來使用,其實(shí)對(duì)于開源框架的二次封裝有時(shí)候針對(duì)不同的業(yè)務(wù)邏輯封裝的過程中也多多少少有些不同
    2023-03-03
  • android查看網(wǎng)絡(luò)圖片的實(shí)現(xiàn)方法

    android查看網(wǎng)絡(luò)圖片的實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了android查看網(wǎng)絡(luò)圖片的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • Android Keystore簽名文件全解析與安全防護(hù)

    Android Keystore簽名文件全解析與安全防護(hù)

    Keystore是存儲(chǔ)加密密鑰、證書和簽名信息的文件(常見格式為.keystore 和.jks),是Android應(yīng)用簽名的核心,用于驗(yàn)證應(yīng)用來源的可靠性,保障分發(fā)過程中的完整性,本文給大家介紹Android Keystore簽名文件全解析與安全防護(hù),感興趣的朋友一起看看吧
    2025-08-08
  • android 軟鍵盤的POPUP布局的問題解決

    android 軟鍵盤的POPUP布局的問題解決

    這篇文章主要介紹了android 軟鍵盤的POPUP布局的問題解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-10-10

最新評(píng)論

阿拉善左旗| 汝州市| 舟山市| 尚义县| 泊头市| 温泉县| 吐鲁番市| 拜城县| 南丹县| 福清市| 安新县| 和平县| 肇源县| 广河县| 洞头县| 青冈县| 香格里拉县| 佛冈县| 同德县| 余姚市| 尼木县| 正宁县| 壶关县| 滨海县| 梅州市| 区。| 新蔡县| 永善县| 抚顺市| 湖南省| 两当县| 宜兰市| 楚雄市| 阜康市| 米林县| 平罗县| 米脂县| 温泉县| 连南| 防城港市| 射洪县|