欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Kotlin ViewModelProvider.Factory的使用實例詳解

 更新時間:2023年02月17日 11:27:28   作者:破浪會有時  
這篇文章主要介紹了Kotlin ViewModelProvider.Factory的使用,在我們使用 ViewModel 的時候,我們會發(fā)現(xiàn),有的時候我們需要用到 ViewModelFactory,有的時候不需要

這里,我們將介紹 Kotlin ViewModelProvider.Factory 的作用和使用方式。

在我們使用 ViewModel 的時候,我們會發(fā)現(xiàn),有的時候我們需要用到 ViewModelFactory,有的時候不需要。

這里,我們將介紹 Kotlin ViewModelProvider.Factory 的作用和使用方式。

在我們使用 ViewModel 的時候,我們會發(fā)現(xiàn),有的時候我們需要用到 ViewModelFactory,有的時候不需要。

1 沒有使用到 ViewModelFactory 的例子

下面這個例子中,我們沒有使用到 ViewModelFactory:

MainActivity.kt

class MainActivity : AppCompatActivity() {
    lateinit var viewModel: ListViewModel
    private val countriesAdapter = CountryListAdapter(arrayListOf())
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
        viewModel.refresh()
        countriesList.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = countriesAdapter
        }
        observeViewModel()
    }
    ...
}

ListViewModel.kt

class ListViewModel: ViewModel() {
    private val countriesService = CountriesService.getCountriesService()
    var job: Job? = null
    private val exceptionHandler = CoroutineExceptionHandler{ coroutineContext, throwable ->
        onError("Exception: ${throwable.localizedMessage}")
    }
    // 生命周期感知型組件 MutableLiveData,可以做到在組件處于激活狀態(tài)的時候才會回調相應的方法,從而刷新相應的 UI
    val countries = MutableLiveData<List<Country>>()
    val countryLoadError = MutableLiveData<String?>()
    val loading = MutableLiveData<Boolean>()
    fun refresh() {
        fetchCountries()
    }
    private fun fetchCountries() {
        loading.value = true
        // 通過launch啟動一個攜程回返回一個Job類型的對象實例,我們可以通過job.start()來啟動攜程(如果launch(start = CoroutineStart.LAZY)
        // 這么設置的話),可以通過job.cancel來取消攜程
        job = CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
            val response : Response<List<Country>> = countriesService.getCountries()
            // after we get the response, we hope that we could switch back to main thread and display on screen.
            withContext(Dispatchers.Main) {
                if (response.isSuccessful){
                    countries.value = response.body()
                    countryLoadError.value = null
                    loading.value = false
                } else
                {
                    onError("Error: ${response.message()}")
                }
            }
        }
    }
    private fun onError(message: String) {
        countryLoadError.value = message
        loading.value = false
    }
    override fun onCleared() {
        super.onCleared()
        job?.cancel()
    }
}

這里,我們不糾結代碼中的細節(jié),只觀察 viewModel 如何被定義和使用。

2 使用到 ViewModelFactory 的例子

下面這個例子中,我們、使用到了 ViewModelFactory:

LoginViewModelFactory.kt

class LoginViewModelFactory(
    private  val repository: RegisterRepository,
    private val application: Application
): ViewModelProvider.Factory{
    @Suppress("Unchecked_cast")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if(modelClass.isAssignableFrom(LoginViewModel::class.java)) {
            return LoginViewModel(repository, application) as T
        }
        throw IllegalArgumentException("Unknown View Model Class")
    }
}

LoginViewModel.kt

class LoginViewModel(private val repository: RegisterRepository, application: Application) :
    AndroidViewModel(application), Observable {
    val users = repository.users
    @Bindable
    val inputUsername = MutableLiveData<String>()
    @Bindable
    val inputPassword = MutableLiveData<String>()
    private val viewModelJob = Job()
    private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
...
}

LoginFragment.kt

class LoginFragment : Fragment() {
    private lateinit var loginViewModel: LoginViewModel
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val binding: FragmentLoginBinding = DataBindingUtil.inflate(
            inflater,
            R.layout.fragment_login, container, false
        )
        val application = requireNotNull(this.activity).application
        val dao = RegisterDatabase.getInstance(application).registerDatabaseDao
        val repository = RegisterRepository(dao)
        val factory = LoginViewModelFactory(repository, application)
        loginViewModel = ViewModelProvider(this, factory).get(LoginViewModel::class.java)
        binding.myLoginViewModel = loginViewModel
        binding.lifecycleOwner = this
        loginViewModel.navigatetoRegister.observe(this, Observer { hasFinished->
            if (hasFinished == true){
                Log.i("MYTAG","insidi observe")
                displayUsersList()
                loginViewModel.doneNavigatingRegiter()
            }
        })
        ...
    }
}

3 分析

我們發(fā)現(xiàn),當我們在 MainActivity.kt 中使用 ViewModelProviders 聲明 viewModel 時,我們沒有調用任何 viewModel 的構造函數(shù)。這是因為,ViewModelProviders 在內部為我們管理并調用 ViewModel 的主要構造函數(shù)(primary constructor)并創(chuàng)建 ViewModel 的實例并將實例返回。

如果我們將參數(shù)傳遞給 viewModel 的構造函數(shù)時,其他都不變,這個時候,系統(tǒng)會報錯:RunTimeError。之所以會有這個報錯是因為 ViewModelProviders.of() 方法在內部創(chuàng)建默認的 ViewModelProvider.Factory 實現(xiàn)來創(chuàng)建我們的沒有參數(shù)的 ViewModel(再次注意,這里的 ViewModel 是沒有參數(shù)的)。 因此,當我們在構造函數(shù)中添加參數(shù)時,ViewModelProvider.Factory 的內部實現(xiàn)無法初始化我們這個 ViewModel,因為 ViewModelProvider.Factory 調用了創(chuàng)建 ViewModel 實例的主構造函數(shù)。

所以說,如果在構造函數(shù)中添加參數(shù),則必須創(chuàng)建自己的 ViewModelProvider.Factory 實現(xiàn)來創(chuàng)建 ViewModel 實例。

那么,什么是 ViewModelProvider.Factory?還是剛才的第二個例子,我們把相關的代碼復制在下面:

LoginViewModelFactory.kt

class LoginViewModelFactory(
    private  val repository: RegisterRepository,
    private val application: Application
): ViewModelProvider.Factory{
    @Suppress("Unchecked_cast")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if(modelClass.isAssignableFrom(LoginViewModel::class.java)) {
            return LoginViewModel(repository, application) as T
        }
        throw IllegalArgumentException("Unknown View Model Class")
    }
}

這里有幾點需要注意:

我們可以通過構造函數(shù)或我們喜歡的任何其他模式(Singleton、FactoryPattern 等)將 ViewModel 參數(shù)傳遞給 ViewModelProvider.Factory。 這是因為我們在初始化 ViewModel 時無法在 ActivityFragment 中調用 ViewModel 構造函數(shù),并且我們想設置 ViewModel 構造函數(shù)的參數(shù)值,因此我們需要將參數(shù)值傳遞給

ViewModelProvider.Factory,它將創(chuàng)建 ViewModel。ViewModelProvider.Factory 是一個具有 create 方法的接口。 create 方法負責創(chuàng)建我們的 VeiwModel 的實例。

我們在LoginFragment.kt中是這么實例化 ViewModel 的:

val factory = LoginViewModelFactory(repository, application)
loginViewModel = ViewModelProvider(this, factory).get(LoginViewModel::class.java)

我們將我們的參數(shù)或依賴項傳遞給我們的 ViewModelProvider.Factory,以便它能夠為我們創(chuàng)建 ViewModel。 ViewModelProviders.of(context, factory) 方法獲取我們的 ViewModelProvider.Factory 的實例。

4 結論

現(xiàn)在我們應該很清楚 ViewModelProvider.Factory 的作用和使用方式了。這里做一個簡單的總結:

何時使用 ViewModelProvider.Factory?

如果我們的 ViewModel 有依賴項或參數(shù)傳遞,那么我們應該通過構造函數(shù)傳遞此依賴項(這是傳遞依賴項的最佳方式)。這個時候 ViewModelProvider.Factory 需要被使用。

何時不使用 ViewModelProvider.Factory?

如果我們的 ViewModel 沒有依賴項或參數(shù)傳遞,那么我們將不需要創(chuàng)建自己的 ViewModelProvider.Factory。默認會自動為我們創(chuàng)建 ViewModel。

到此這篇關于Kotlin ViewModelProvider.Factory的使用實例詳解的文章就介紹到這了,更多相關Kotlin ViewModelProvider.Factory內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論