有没有办法从片段内部访问Activity的ViewModel?或者最好通过在每个片段中重新创建 ViewModel ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication()).create(CanteensViewModel.class); 不是在Activity中创建它?当我使用ViewModelProvider的其他构造函数时,它似乎起作用了,其中AndroidViewModelFactory是第二个参数. new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(CanteensViewModel.class); 在MainActivity中执行此操作,我可以通过访问Fragment中的CanteensViewModel new ViewModelProvider(requireActivity()).get(CanteensViewModel.class); 编辑2上述异常的Stacktrace: 2020-02-28 14:30:16.098 25279-25279/com.pasta.mensadd E/AndroidRuntime: FATAL EXCEPTION: main Process: com.pasta.mensadd, PID: 25279 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.pasta.mensadd/com.pasta.mensadd.ui.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.pasta.mensadd.ui.viewmodel.CanteensViewModel at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2795) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6543) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.RuntimeException: Cannot create an instance of class com.pasta.mensadd.ui.viewmodel.CanteensViewModel at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) at com.pasta.mensadd.ui.MainActivity.onCreate(MainActivity.java:70) at android.app.Activity.performCreate(Activity.java:7023) at android.app.Activity.performCreate(Activity.java:7014) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2748) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6543) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.InstantiationException: java.lang.Class<com.pasta.mensadd.ui.viewmodel.CanteensViewModel> has no zero argument constructor at java.lang.Class.newInstance(Native Method) at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) at com.pasta.mensadd.ui.MainActivity.onCreate(MainActivity.java:70) at android.app.Activity.performCreate(Activity.java:7023) at android.app.Activity.performCreate(Activity.java:7014) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2748) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6543) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) ```解决方案 所以我检查了文档,据我所知,我现在应该使用ViewModelProvider.AndroidViewModelFactory.getInstance( this.getApplication()).create(CanteensViewModel.class);请分享指向您提到的文档"的链接,因为这不是我第一次看到此代码,但是在两种情况下都是错误的.您实际上应该使用的代码是new ViewModelProvider(this).get(CanteensViewModel.class); 有没有办法可以从片段内部访问Activity的ViewModel?还是最好通过以下方式在每个片段中重新创建ViewModelnew ViewModelProvider(requireActivity()).get(CanteensViewModel.class);考虑还会在您的AndroidViewModel中接收到SavedStateHandle作为参数,而不仅仅是Application .如果您问我,显然删除ViewModelProviders.of()是API错误,但这就是我们现在要拥有的. 编辑:借助所提供的堆栈跟踪,我终于可以弄清楚发生了什么. at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)我们使用NewInstanceFactory作为默认值.默认NewInstanceFactory有什么作用? 如果可用,它只会调用无参数构造函数.等等,什么?它不是应该为AndroidViewModel填写Application吗?从理论上讲,是的,只要您使用了默认的默认值ViewModelProvider.Factory,但这不是一个!为什么不是可以填充AndroidViewModel的那个?请参见此提交Add default ViewModel Factory interfaceUse a marker interface to allow instances ofViewModelStoreOwner, such as ComponentActivityand Fragment, to provide a defaultViewModelProvider.Factory that can be used witha new, concise ViewModelProvider constructor.This updates ComponentActivity and Fragment touse that new API to provide anAndroidViewModelFactory by default. It updatesthe 'by viewModels' Kotlin extensions to usethis default Factory if one isn't explicitlyprovided.也ComponentActivity:+ @NonNull+ @Override+ public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {+ if (getApplication() == null) {+ throw new IllegalStateException("Your activity is not yet attached to the "+ + "Application instance. You can't request ViewModel before onCreate call.");+ }+ return ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());+ }+最重要的是public ViewModelProvider(@NonNull ViewModelStoreOwner owner) { this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance());}这意味着您将获得默认的视图模型提供程序工厂,该工厂可以正确设置AndroidViewModel.如果 ViewModelStoreOwner实现了HasDefaultViewModelProviderFactory.从理论上讲,ComponentActivity确实是HasDefaultViewModelProviderFactory;和AppCompatActivity从ComponentActivity扩展.在您的情况下,情况似乎并非如此.由于某些原因,您的AppCompatActivity不是HasDefaultViewModelProviderFactory.我认为解决您的问题的方法是将Lifecycle更新为2.2.0,并将ALOC也将implementation 'androidx.core:core-ktx更新为至少 1.2.0. (具体来说,至少是AndroidX-Activity 1.1.0和AndroidX-Fragment 1.2.0).In the summer of last year I started refactoring my Android application with Android's architecture components (Room, ViewModel, LiveData).I have two Room repositories, one of them is accessed by multiple views (fragments) of the application. Because of that I used an AndroidViewModel, which has access to this repository and which is initialized in my MainActivity.new ViewModelProvider(this).get(CanteensViewModel.class);In my two fragments I accessed this ViewModel bynew ViewModelProvider(getActivity()).get(CanteensViewModel.class);Until yesterday that worked perfectly. But then I updated my dependencies and since androidx.lifecycle version 2.2.0 this does not work anymore. I always get an exception (siehe EDIT 2):Caused by: java.lang.InstantiationException: java.lang.Class<com.(...).CanteensViewModel> has no zero argument constructorSo I checked the docs and as I understood right I should/could now useViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()).create(CanteensViewModel.class);to get my ViewModel. But with this approach I can't add the owner (parameter of ViewModelProviders constructor), which results in the problem, that I can't really access the ViewModel I created in the Activity from inside my fragments.Is there a way I can access the Activity's ViewModel from inside the fragments? Or would it be better to recreate the ViewModel in each fragment by ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication()).create(CanteensViewModel.class);instead of creating it inside the Activity?EDIT:It seems to work, when I use the other constructor of ViewModelProvider, where a AndroidViewModelFactory is the second parameter.new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(CanteensViewModel.class);Doing this in my MainActivity I can access the CanteensViewModel in my Fragment vianew ViewModelProvider(requireActivity()).get(CanteensViewModel.class);EDIT 2Stacktrace for above mentioned exception:2020-02-28 14:30:16.098 25279-25279/com.pasta.mensadd E/AndroidRuntime: FATAL EXCEPTION: main Process: com.pasta.mensadd, PID: 25279 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.pasta.mensadd/com.pasta.mensadd.ui.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.pasta.mensadd.ui.viewmodel.CanteensViewModel at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2795) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6543) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.RuntimeException: Cannot create an instance of class com.pasta.mensadd.ui.viewmodel.CanteensViewModel at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) at com.pasta.mensadd.ui.MainActivity.onCreate(MainActivity.java:70) at android.app.Activity.performCreate(Activity.java:7023) at android.app.Activity.performCreate(Activity.java:7014) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2748) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6543) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.InstantiationException: java.lang.Class<com.pasta.mensadd.ui.viewmodel.CanteensViewModel> has no zero argument constructor at java.lang.Class.newInstance(Native Method) at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) at com.pasta.mensadd.ui.MainActivity.onCreate(MainActivity.java:70) at android.app.Activity.performCreate(Activity.java:7023) at android.app.Activity.performCreate(Activity.java:7014) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2748) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1602) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6543) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) ``` 解决方案 So I checked the docs and as I understood right I should now useViewModelProvider.AndroidViewModelFactory.getInstance( this.getApplication()).create(CanteensViewModel.class);Please share a link to this "docs" you mentioned, because this is NOT the first time I see this code, and yet it was equally wrong in both cases.The code you actually should be using isnew ViewModelProvider(this).get(CanteensViewModel.class); Is there a way I can access the Activity's ViewModel from inside the fragments? Or would it be better to recreate the ViewModel in each fragment bynew ViewModelProvider(requireActivity()).get(CanteensViewModel.class);Consider also receiving a SavedStateHandle as an argument in your AndroidViewModel, and not only Application.If you ask me, apparently the removal of ViewModelProviders.of() was an API mistake, but this is what we have now.EDIT: With the help of the provided stack trace, I can finally somewhat figure out what's going on. at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)We are using NewInstanceFactory as the default. What does default NewInstanceFactory do? It just calls no-arg constructor if available.Wait, what? Isn't it supposed to fill in the Application for an AndroidViewModel?Theoretically yes, as long as you got the original default ViewModelProvider.Factory, but this is not the one!Why is it not the one that can fill in AndroidViewModel?See this commitAdd default ViewModel Factory interfaceUse a marker interface to allow instances ofViewModelStoreOwner, such as ComponentActivityand Fragment, to provide a defaultViewModelProvider.Factory that can be used witha new, concise ViewModelProvider constructor.This updates ComponentActivity and Fragment touse that new API to provide anAndroidViewModelFactory by default. It updatesthe 'by viewModels' Kotlin extensions to usethis default Factory if one isn't explicitlyprovided.AlsoComponentActivity:+ @NonNull+ @Override+ public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {+ if (getApplication() == null) {+ throw new IllegalStateException("Your activity is not yet attached to the "+ + "Application instance. You can't request ViewModel before onCreate call.");+ }+ return ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());+ }+And most importantlypublic ViewModelProvider(@NonNull ViewModelStoreOwner owner) { this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance());}This means that you get the default view model provider factory that can properly set up AndroidViewModel if the ViewModelStoreOwner implements HasDefaultViewModelProviderFactory.Theoretically, ComponentActivity is indeed a HasDefaultViewModelProviderFactory; and AppCompatActivity extends from ComponentActivity.In your case however, that doesn't seem to be the case. For some reason, your AppCompatActivity is not HasDefaultViewModelProviderFactory.I think the solution to your problem is to update Lifecycle to 2.2.0, and ALSO update implementation 'androidx.core:core-ktx to at least 1.2.0. (specifically at least AndroidX-Activity 1.1.0, and AndroidX-Fragment 1.2.0). 这篇关于可以通过Fragment访问Activity的AndroidViewModel吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 09-02 21:45