[英]How can I create a function that I can access from both a ViewModel and Activity?
I am building an android app that has a MainActivity and several fragments.我正在构建一个具有 MainActivity 和几个片段的 android 应用程序。 I am using a ViewModel and ViewModelFactory for each of the fragments.我为每个片段使用 ViewModel 和 ViewModelFactory。 I need to create a function that will perform network requests and would like to have it available in one of the fragments so I can display a progress bar to the user.我需要创建一个 function 来执行网络请求,并希望它在其中一个片段中可用,这样我就可以向用户显示一个进度条。 I would also like to access this function from MainActivity in the override function onOptionsItemSelected when a user clicks on the button in the menu in the top right.当用户单击右上角菜单中的按钮时,我还想在覆盖 function onOptionsItemSelected 中从 MainActivity 访问此 function。 When called from this button everything should be in the background and there is no need to show the user anything until the task is completed.从这个按钮调用时,一切都应该在后台,并且在任务完成之前不需要向用户显示任何内容。
I have tried two approaches.我尝试了两种方法。
I placed this in MainActivity before onCreate我在 onCreate 之前把它放在 MainActivity
private lateinit var syncViewModel: SyncViewModel
And this in onCreate这在 onCreate
syncViewModel = ViewModelProvider(this).get(SyncViewModel::class.java)
And I get the below error message.我收到以下错误消息。
java.lang.RuntimeException: Unable to start activity ComponentInfo java.lang.RuntimeException: Cannot create an instance of class com. java.lang.RuntimeException: Unable to start activity ComponentInfo java.lang.RuntimeException: Cannot create an instance of class com. . . ._.SyncViewModel ._.SyncViewModel
How can I access the already created ViewModel from the activity instead of creating one?如何从活动中访问已经创建的 ViewModel 而不是创建一个?
In the ViewModel I have the below, and then the xml in this fragment references this syncProgress value.在 ViewModel 中,我有以下内容,然后这个片段中的 xml 引用了这个 syncProgress 值。
private var _syncProgress = MutableLiveData<Int>()
val syncProgress: LiveData<Int> = _syncProgress
What am I missing to connect this separate function to be able to update the values in my ViewModel?我缺少什么来连接这个单独的 function 以便能够更新我的 ViewModel 中的值?
It seems like option #1 is the right way to do this, but maybe there is a third way that I dont know about that would be better!似乎选项#1是正确的方法,但也许有第三种我不知道的方法会更好! Any help is appreciated!任何帮助表示赞赏!
Update 1更新 1
My ViewModel is defined as我的 ViewModel 定义为
class SyncViewModel(
val database: RoomDatabase,
application: Application) : AndroidViewModel(application) {
And in the fragment as在片段中
// 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)
But I am not sure how I need to modify the SyncViewModel in MainActivity?但我不确定我需要如何修改 MainActivity 中的 SyncViewModel?
I would follow your option 1, and use view model provider delegates to simplify getting your reference.我会遵循您的选项 1,并使用视图 model 提供者代表来简化获取您的参考。 You should specify an Activity-scoped ViewModel in the Fragment so it gets the same instance that the Activity gets.您应该在 Fragment 中指定一个 Activity 范围的 ViewModel,以便它获得与 Activity 相同的实例。
In your Activity:在您的活动中:
private val syncViewModel: SyncViewModel by viewModels()
In your Fragment:在你的片段中:
private val syncViewModel: SyncViewModel by activityViewModels()
Since your database can be acquired using the Application instance, you can avoid creating a factory by moving it out of the constructor like this:由于可以使用 Application 实例获取数据库,因此可以通过将其移出构造函数来避免创建工厂,如下所示:
class SyncViewModel(application: Application) : AndroidViewModel(application) {
val database = RoomDatabase.getDatabase(application)
If you do want to continue using your factory, you can pass it as a parameter to the delegate functions, for example:如果您确实想继续使用您的工厂,可以将其作为参数传递给委托函数,例如:
private val dataSource = RoomDatabase.getDatabase(application)
private val syncViewModel: SyncViewModel by activityViewModels(SyncViewModelFactory(dataSource, application))
If I understand correctly the function should be outside of the ViewModel because it has to be accessed in other places too.如果我理解正确,function 应该在 ViewModel 之外,因为它也必须在其他地方访问。
The LiveData in the ViewModel won't get updated on the state of the function but one way to fix this would be to just make the ViewModel immediately "listen" to whatever the function's current state is. ViewModel 中的 LiveData 不会在 function 的 state 上更新,但解决此问题的一种方法是让 ViewModel 立即“监听”函数当前的 Z9ED39E2EA931586B6EZEFA 是什么。
Let's say you would normally update the value/progress from 0 to 100 in a Repository, update a LiveData object with that progress and make the ViewModel or/and Activity listen to it.假设您通常会在存储库中将值/进度从 0 更新到 100,用该进度更新 LiveData object 并让 ViewModel 或/和 Activity 监听它。 LiveData in Repositories isn't something that's perfect but it seems like a solution based on what I read.存储库中的 LiveData 不是完美的,但它似乎是基于我阅读的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.