标签: android-viewmodel

Android ViewModel 的职责是仅保存数据还是保存数据+视图控制器?

官方得知

ViewModel 类旨在以生命周期意识的方式存储和管理 UI 相关数据

但我认为很多开发人员ViewModel同时用作数据存储和控制器(例如调用存储库、数据的网络客户端)。我还使用 as 作为数据存储和视图控制器。

Android官方示例代码也有一些控制器逻辑。来自官方

class MyViewModel : ViewModel() {
  private val users: MutableLiveData<List<User>> by lazy {
     MutableLiveData().also {
        loadUsers()
     }
  }

  fun getUsers(): LiveData<List<User>> {
    return users
  }

  private fun loadUsers() {
    // Do an asynchronous operation to fetch users.
  }
}
Run Code Online (Sandbox Code Playgroud)

这里loadUsers可能会调用一些RepositoryNetworkClient。所以在这里它就像控制器一样。

我确信许多开发人员都这样做,但从定义上看ViewModel应该存储和管理 UI 相关数据,应该ViewModel充当控制器吗?

我发现了一些 stackoverflow 线程这个这个关于这个。

第一个接受的答案建议不要用作ViewModel控制器并使用 …

android android-mvp android-viewmodel android-architecture-components

5
推荐指数
1
解决办法
2057
查看次数

如何检查给定 ViewModelProvider 的 ViewModel 是否已存在

该视频(MVVM 和嵌套片段/视图:ViewModel 合约 - Marcos Paulo Damesceno、Bret Erickson droidcon 旧金山 2019)展示了一种使用ViewModel.

我出于学习目的而实施它,但我陷入了困境。

// 18:35 of the video

private const val VM_KEY = "view_model_contract_key"

fun <T> Fragment.viewModelContracts() = lazy {
    val clazz: Class<ViewModel> = arguments?.getSerializable(VM_KEY) as Class<ViewModel>
    val viewModelProvider = ViewModelProvider(requireActivity())

    return@lazy viewModelProvider.get(clazz) as T
}
Run Code Online (Sandbox Code Playgroud)

传递的参数ViewModelStoreOwner是 an Activity,但是如果我有一个Fragment内部的另一个对象Fragment,并且它们共享相同的对象ViewModel,则ViewModel返回的对象viewModelContracts()将是与 Parent 创建的对象不同的对象Fragment

interface ChildViewModelContract {
    // ...
}

class SomeViewModel : ViewModel(), ChildViewModelContract { …
Run Code Online (Sandbox Code Playgroud)

android android-fragments android-viewmodel

5
推荐指数
0
解决办法
864
查看次数

如何测试注入 Koin 的 viewModel?

我有一个视图模型。它调用我的数据存储库中的函数并返回狗对象的列表。

class MainViewModel() : ViewModel() {
    private val dataRepo: DataRepo by inject(DataRepo::class.java) //dataRepo
    private var limit = 10
    private val _dogListLiveData = MutableLiveData<List<Dog>>()
    private var dogList = mutableListOf<Dog>()

    val dogListLiveData: MutableLiveData<List<Dog>>
        get() = _dogListLiveData

    fun searchByBreed(queryText: String) {
        dataRepo.searchByBreed(
            queryText,
            object : DataSource.OnResponseCallback<List<Dog>, String> {
                override fun onSuccess(obj: List<Dog>?) {
                    dogList = mutableListOf()
                    if(!obj.isNullOrEmpty()){
                    dogList.addAll(obj)
                    dogListLiveData.value = dogList.take(limit)
                    }

                }

                override fun onError(error: String) {
                    Log.i("Calling Network Service", error)
                }
            })

    }

    fun loadPaginateBreed() : Boolean{
        return if ((limit+10) < …
Run Code Online (Sandbox Code Playgroud)

java android kotlin android-viewmodel koin

5
推荐指数
1
解决办法
3583
查看次数

如何在一组特定的 Fragments 之间共享 ViewModel 范围,而不使用 NavGraph 或将其范围限定到活动?

谷歌表示,在 Fragment 之间进行通信时,通过将其范围限定为 Activity 来使用 SharedViewModel。

在单个 Activity 应用程序中,这意味着该 Activity 将散布着可能不再需要的 ViewModel,并且它们将在整个生命周期中保留在那里。考虑一些示例,例如扩展的注册流程或考虑几个屏幕的示例。

推荐的一种方法是使用父片段作为范围,但这只有在存在父片段时才可能。它可以只是不同的片段。

我想出了以下解决方案,我想知道它有多可行或有多糟糕,是否有更好的方法?

考虑到我有两个名为ExampleOneFragmentand的片段ExampleTwoFragment,为了简单起见,我希望它们具有共享范围,而不实际将其范围限定到活动。假设我想更新其中的文本视图ExampleOneFragmentExampleTwoFragment因此我为两者创建一个像这样的 SharedViewModel

因为ExampleOneFragment它将是:

 private val mSharedViewModel by lazy {
    ViewModelProvider(this).get(SharedViewModel::class.java)
}
Run Code Online (Sandbox Code Playgroud)

因为ExampleTwoFragment我想出了这个:

private val mSharedViewModel by lazy {
    ViewModelProvider(supportFragmentManager().findFragmentByTag(ExampleOneFragment.TAG) ?: this).get(SharedViewModel::class.java)
}
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但我不知道这会导致什么样的问题。

我发现了一些其他解决方案:根据@mikhehc这里,我们实际上可以创建我们自己的 ViewModelStore。这将使我们能够精细地控制 ViewModel 必须存在的范围。但我不明白如何让它适用于片段?

其次,仍然是将其范围限定为活动的黑客方法,但使用我在此处找到的相同密钥通过虚拟视图模型将其清除

谁能指导我什么是正确的方法?我无法转向 NavGraphs,因为它是一个已经启动并正在运行的项目,并且确定活动范围感觉是错误的。谢谢。

android android-fragments android-navigation android-viewmodel android-architecture-navigation

5
推荐指数
1
解决办法
1180
查看次数

在 ViewModel 与 LifeCycleOwner 中启动协程(活动/片段)

是在 ViewModel 中启动协程更好,还是用suspend修饰符标记 ViewModel 函数并在 Activity/fragment 本身中启动协程更好?

在 ViewModel 中启动:

class MainViewModel: ViewModel() {
  fun addNewItem(item: Item) {
    viewModelScope.launch {
      // Add the item to database
    }
  }
}
Run Code Online (Sandbox Code Playgroud)
class ItemsFragment: Fragment() {
  fun onButtonClick() {
    viewModel.addNewItem(Item())
  }
}
Run Code Online (Sandbox Code Playgroud)

在 LifeCycleOwner 中启动:

class MainViewModel: ViewModel() {
  suspend fun addNewItem(item: Item) {
    // Add the item to database
  }
}
Run Code Online (Sandbox Code Playgroud)
class ItemsFragment: Fragment() {
  fun onButtonClick() {
    lifecycleScope.launchWhenStarted {
      viewModel.addNewItem(Item())
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

android kotlin android-viewmodel kotlin-coroutines coroutinescope

5
推荐指数
1
解决办法
1607
查看次数

Android:一个 ViewModel 可以用于多个 Fragments 吗?

我有一个关于 Android 应用程序架构的一般性问题。我正在实现一个应用程序(用Java),它有一个活动和20个片段(相似但不相同)。到目前为止,我在片段中实现了所有内容(UI、逻辑、数据库查询)。现在我正在考虑使用 ViewModel,但我不确定它是否值得付出努力。所以我的问题是我的 20 个片段中的每一个片段是否都应该有一个自己的 ViewModel,或者我是否可以为所有 20 个片段实现一个 ViewModel?为所有 Fragment 类实现一个 ViewModel 会大大增加工作量,所以我想知道是否可以为所有 Fragment 只使用一个 ViewModel ?

android android-fragments android-viewmodel

5
推荐指数
1
解决办法
9403
查看次数

将 Koin 升级到 3.1.3 时,使用共享视图模型的 Android 测试失败,并出现 java.lang.ClassCastException androidx.lifecycle.SavedStateHandleController

我目前正在使用 Koin 版本 3.1.0 并想升级到最新版本(当前为 3.1.4),但是一旦我将 Koin 升级到 3.1.3 以上,我在运行测试时会出现以下异常:

class java.lang.Object cannot be cast to class androidx.lifecycle.SavedStateHandleController (java.lang.Object is in module java.base of loader 'bootstrap'; androidx.lifecycle.SavedStateHandleController is in unnamed module of loader org.robolectric.internal.AndroidSandbox$SdkSandboxClassLoader @5c2a3b10)
java.lang.ClassCastException: class java.lang.Object cannot be cast to class androidx.lifecycle.SavedStateHandleController (java.lang.Object is in module java.base of loader 'bootstrap'; androidx.lifecycle.SavedStateHandleController is in unnamed module of loader org.robolectric.internal.AndroidSandbox$SdkSandboxClassLoader @5c2a3b10)
    at androidx.lifecycle.SavedStateHandleController.attachHandleIfNeeded(SavedStateHandleController.java:98)
    at androidx.lifecycle.AbstractSavedStateViewModelFactory.onRequery(AbstractSavedStateViewModelFactory.java:103)
    at androidx.lifecycle.StateViewModelFactory.onRequery(StateViewModelFactory.kt:37)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:160)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
    at org.koin.androidx.viewmodel.ViewModelResolverKt.resolveInstance(ViewModelResolver.kt:15)
    at org.koin.androidx.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:67)
    at org.koin.androidx.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:53)
    at org.koin.androidx.viewmodel.scope.ScopeExtKt.getViewModel$default(ScopeExt.kt:45)
    at …
Run Code Online (Sandbox Code Playgroud)

android classcastexception robolectric android-viewmodel koin

5
推荐指数
1
解决办法
549
查看次数

无法创建类视图模型的实例 - Kotlin

我目前正在开发一个项目来练习使用 Dagger-Hilt 进行依赖注入,但是我无法实例化我的 ViewModel,我已经查看了同一主题的其他一些问题,大多数问题都指向 Gradle,但是没有为我修复它,Stacktrace 中的所有错误都来自内部类,除了 MainActivity 中涉及我的 ViewModel 的两行之外

\n

这是堆栈跟踪:

\n
E/AndroidRuntime: FATAL EXCEPTION: main\nProcess: com.example.practiceproject, PID: 9873\njava.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.practiceproject/com.example.practiceproject.ui.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.practiceproject.ui.viewmodel.DogViewModel\n    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)\n    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)\n    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)\n    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)\n    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)\n    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)\n    at android.os.Handler.dispatchMessage(Handler.java:107)\n    at android.os.Looper.loop(Looper.java:214)\n    at android.app.ActivityThread.main(ActivityThread.java:7356)\n    at java.lang.reflect.Method.invoke(Native Method)\n    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)\n    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)\n Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.practiceproject.ui.viewmodel.DogViewModel\n    at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)\n    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)\n    at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)\n    at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:146)\n    at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:111)\n    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)\n …
Run Code Online (Sandbox Code Playgroud)

android viewmodel kotlin android-viewmodel

5
推荐指数
2
解决办法
1万
查看次数

使用 viewPager2 在 Fragment 之间共享 ViewModel

我有一个 Fragment0,其中包含一个 ViewPager2,该 ViewPager2 内部可能包含 1 个或多个子片段。

在此输入图像描述

我创建了一个 SharedViewModel 并在 Parent 片段中定义它,如下所示:

val viewModel by viewModels<SharedViewModel>()
Run Code Online (Sandbox Code Playgroud)

我还在每个子片段中添加了 viewModel 的定义。

private val sharedViewModel by viewModels<SharedViewModel>(
    ownerProducer = { requireParentFragment() }
)
Run Code Online (Sandbox Code Playgroud)

我使用 NavigationControl 从每个子片段即导航到 Fragment4。片段 1、片段 2 和片段 3。我的问题是,如何与 Fragment4 共享相同的视图模型,它不是 Fragment0 的直接子级。我可以使用相同的方法与 Fragment4 共享 viewModel 吗?

或者有更好的方法来处理这样的用例吗?

android viewmodel android-fragments kotlin android-viewmodel

5
推荐指数
1
解决办法
1558
查看次数

使用 hilt 将 Activity 中的视图模型共享到 compose 函数

我的应用程序使用 hilt,我LoadManager在活动内部进行了一些工作,使用读取联系人ContentResolver,当我完成工作时,我得到发送到我的 viewModel 的光标,以便处理数据并执行一些业务逻辑,为此我声明了以下内容在我的活动之上:

@AndroidEntryPoint
class MainActivity : ComponentActivity(), LoaderManager.LoaderCallbacks<Cursor> {
    private val contactsViewModel: ContactsViewModel by viewModels()
 ...
Run Code Online (Sandbox Code Playgroud)

这样我就可以在里面使用它onLoadFinished

    override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) {
  
                contactsViewModel.updateContactsListFromCursor(cursor, loader.id)
     }

Run Code Online (Sandbox Code Playgroud)

在我的 viewModel 中,我有以下代码,它使用要显示的联系人更新列表的 ui 状态:

data class ContactsListUiState(
    val contacts: MutableList<Contact>,
    val searchFilter: String)

@HiltViewModel
class ContactsViewModel @Inject constructor() : ViewModel() {
    private val _contactsListUiState =
        MutableStateFlow(ContactsListUiState(mutableStateListOf(), ""))
    val contactsListUiState: StateFlow<ContactsListUiState> = _contactsListUiState.asStateFlow()

    private fun updateContactsList(filter: String) {
        viewModelScope.launch(Dispatchers.IO) {
            ...

            _contactsListUiState.update { currentState -> …
Run Code Online (Sandbox Code Playgroud)

android android-viewmodel android-jetpack-compose dagger-hilt jetpack-compose-navigation

5
推荐指数
1
解决办法
2814
查看次数