如何创建一个可以从 ViewModel 和 Activity 访问的函数?
How can I create a function that I can access from both a ViewModel and Activity?
我正在构建一个 android 应用程序,它有一个 MainActivity 和几个片段。我为每个片段使用 ViewModel 和 ViewModelFactory。我需要创建一个函数来执行网络请求,并希望它在其中一个片段中可用,以便我可以向用户显示进度条。当用户单击右上角菜单中的按钮时,我还想从覆盖函数 onOptionsItemSelected 中的 MainActivity 访问此函数。当从这个按钮调用时,一切都应该在后台,在任务完成之前不需要向用户显示任何东西。
我试过两种方法。
- 将函数放在 ViewModel 中。这非常适合从片段调用并且一切正常。但是当从 Main activity 调用时,我似乎无法正确引用 ViewModel。
我把它放在了 onCreate 之前的 MainActivity 中
private lateinit var syncViewModel: SyncViewModel
这在 onCreate
syncViewModel = ViewModelProvider(this).get(SyncViewModel::class.java)
我收到以下错误消息。
java.lang.RuntimeException:无法启动 activity ComponentInfo java.lang.RuntimeException:无法创建 class com.. 的实例。 _.SyncViewModel
如何从 activity 访问已经创建的 ViewModel 而不是创建一个?
- 所以我的第二次尝试是将这个函数放在一个单独的文件中。然后我可以从 ViewModel 和 MainActivity 访问它。但是我找不到在 ViewModel 中更新进度条的方法。
在 ViewModel 中我有以下内容,然后此片段中的 xml 引用此 syncProgress 值。
private var _syncProgress = MutableLiveData<Int>()
val syncProgress: LiveData<Int> = _syncProgress
我缺少什么来连接这个单独的函数以更新我的 ViewModel 中的值?
似乎选项 #1 是执行此操作的正确方法,但也许还有第三种我不知道的方法会更好!
感谢您的帮助!
更新 1
我的 ViewModel 定义为
class SyncViewModel(
val database: RoomDatabase,
application: Application) : AndroidViewModel(application) {
并且在片段中为
// Create an Instance of the ViewModel Factory
val dataSource = RoomDatabase.getDatabase(application)
val viewModelFactory = SyncViewModelFactory(dataSource, application)
private lateinit var syncViewModel: SyncViewModel
syncViewModel = ViewModelProvider(this,viewModelFactory).get(SyncViewModel::class.java)
但是我不确定我需要如何修改 MainActivity 中的 SyncViewModel?
我会遵循您的选项 1,并使用视图模型提供程序委托来简化您的参考。您应该在片段中指定一个 Activity 范围的 ViewModel,以便它获得与 Activity 相同的实例。
在你的Activity中:
private val syncViewModel: SyncViewModel by viewModels()
在你的片段中:
private val syncViewModel: SyncViewModel by activityViewModels()
由于可以使用 Application 实例获取数据库,因此可以通过将其移出构造函数来避免创建工厂,如下所示:
class SyncViewModel(application: Application) : AndroidViewModel(application) {
val database = RoomDatabase.getDatabase(application)
如果您确实想继续使用您的工厂,您可以将其作为参数传递给委托函数,例如:
private val dataSource = RoomDatabase.getDatabase(application)
private val syncViewModel: SyncViewModel by activityViewModels(SyncViewModelFactory(dataSource, application))
如果我理解正确,该函数应该在 ViewModel 之外,因为它也必须在其他地方访问。
ViewModel 中的 LiveData 不会根据函数的状态进行更新,但解决此问题的一种方法是让 ViewModel 立即“监听”函数的当前状态。
假设您通常会在 Repository 中将 value/progress 从 0 更新到 100,用该进度更新 LiveData 对象并让 ViewModel or/and Activity 监听它。 Repositories 中的 LiveData 不是完美的东西,但它似乎是基于我阅读的内容的解决方案。
我正在构建一个 android 应用程序,它有一个 MainActivity 和几个片段。我为每个片段使用 ViewModel 和 ViewModelFactory。我需要创建一个函数来执行网络请求,并希望它在其中一个片段中可用,以便我可以向用户显示进度条。当用户单击右上角菜单中的按钮时,我还想从覆盖函数 onOptionsItemSelected 中的 MainActivity 访问此函数。当从这个按钮调用时,一切都应该在后台,在任务完成之前不需要向用户显示任何东西。
我试过两种方法。
- 将函数放在 ViewModel 中。这非常适合从片段调用并且一切正常。但是当从 Main activity 调用时,我似乎无法正确引用 ViewModel。
我把它放在了 onCreate 之前的 MainActivity 中
private lateinit var syncViewModel: SyncViewModel
这在 onCreate
syncViewModel = ViewModelProvider(this).get(SyncViewModel::class.java)
我收到以下错误消息。
java.lang.RuntimeException:无法启动 activity ComponentInfo java.lang.RuntimeException:无法创建 class com.. 的实例。 _.SyncViewModel
如何从 activity 访问已经创建的 ViewModel 而不是创建一个?
- 所以我的第二次尝试是将这个函数放在一个单独的文件中。然后我可以从 ViewModel 和 MainActivity 访问它。但是我找不到在 ViewModel 中更新进度条的方法。
在 ViewModel 中我有以下内容,然后此片段中的 xml 引用此 syncProgress 值。
private var _syncProgress = MutableLiveData<Int>()
val syncProgress: LiveData<Int> = _syncProgress
我缺少什么来连接这个单独的函数以更新我的 ViewModel 中的值?
似乎选项 #1 是执行此操作的正确方法,但也许还有第三种我不知道的方法会更好! 感谢您的帮助!
更新 1
我的 ViewModel 定义为
class SyncViewModel(
val database: RoomDatabase,
application: Application) : AndroidViewModel(application) {
并且在片段中为
// Create an Instance of the ViewModel Factory
val dataSource = RoomDatabase.getDatabase(application)
val viewModelFactory = SyncViewModelFactory(dataSource, application)
private lateinit var syncViewModel: SyncViewModel
syncViewModel = ViewModelProvider(this,viewModelFactory).get(SyncViewModel::class.java)
但是我不确定我需要如何修改 MainActivity 中的 SyncViewModel?
我会遵循您的选项 1,并使用视图模型提供程序委托来简化您的参考。您应该在片段中指定一个 Activity 范围的 ViewModel,以便它获得与 Activity 相同的实例。
在你的Activity中:
private val syncViewModel: SyncViewModel by viewModels()
在你的片段中:
private val syncViewModel: SyncViewModel by activityViewModels()
由于可以使用 Application 实例获取数据库,因此可以通过将其移出构造函数来避免创建工厂,如下所示:
class SyncViewModel(application: Application) : AndroidViewModel(application) {
val database = RoomDatabase.getDatabase(application)
如果您确实想继续使用您的工厂,您可以将其作为参数传递给委托函数,例如:
private val dataSource = RoomDatabase.getDatabase(application)
private val syncViewModel: SyncViewModel by activityViewModels(SyncViewModelFactory(dataSource, application))
如果我理解正确,该函数应该在 ViewModel 之外,因为它也必须在其他地方访问。
ViewModel 中的 LiveData 不会根据函数的状态进行更新,但解决此问题的一种方法是让 ViewModel 立即“监听”函数的当前状态。
假设您通常会在 Repository 中将 value/progress 从 0 更新到 100,用该进度更新 LiveData 对象并让 ViewModel or/and Activity 监听它。 Repositories 中的 LiveData 不是完美的东西,但它似乎是基于我阅读的内容的解决方案。