jul*_*tni 8 android viewmodel android-architecture-components
去年夏天,我开始使用 Android 的架构组件(Room、ViewModel、LiveData)重构我的 Android 应用程序。
我有两个 Room 存储库,其中一个由应用程序的多个视图(片段)访问。因此,我使用了AndroidViewModel,它可以访问此存储库并在我的MainActivity.
new ViewModelProvider(this).get(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
在我的两个片段中,我通过
new ViewModelProvider(getActivity()).get(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
直到昨天,这一切都完美无缺。但是后来我更新了我的依赖项,从androidx.lifecycle2.2.0 版开始这不再起作用了。我总是得到一个例外(siehe EDIT 2):
Caused by: java.lang.InstantiationException: java.lang.Class<com.(...).CanteensViewModel> has no zero argument constructor
Run Code Online (Sandbox Code Playgroud)
所以我检查了文档,正如我理解的那样,我现在应该/可以使用
ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()).create(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
获取我的 ViewModel。但是使用这种方法我无法添加owner( ViewModelProviders 构造函数的参数),这导致了问题,即我无法从片段内部真正访问我在 Activity 中创建的 ViewModel。
有没有办法可以从片段内部访问 Activity 的 ViewModel?或者最好通过以下方式在每个片段中重新创建ViewModel
ViewModelProvider.AndroidViewModelFactory.getInstance(getActivity().getApplication()).create(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
而不是在活动中创建它?
编辑:
当我使用 的另一个构造函数时ViewModelProvider,它似乎有效,其中 aAndroidViewModelFactory是第二个参数。
new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
在我的MainActivity我可以访问CanteensViewModel我的Fragment通过
new ViewModelProvider(requireActivity()).get(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
针对上述异常编辑 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)
```
Run Code Online (Sandbox Code Playgroud)
Epi*_*rce 13
所以我检查了文档,正如我理解的那样,我现在应该使用
Run Code Online (Sandbox Code Playgroud)ViewModelProvider.AndroidViewModelFactory.getInstance( this.getApplication()).create(CanteensViewModel.class);
请分享您提到的此“文档”的链接,因为这不是我第一次看到此代码,但在两种情况下都同样错误。
您实际应该使用的代码是
new ViewModelProvider(this).get(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
有没有办法可以从片段内部访问 Activity 的 ViewModel?或者最好通过以下方式在每个片段中重新创建 ViewModel
new ViewModelProvider(requireActivity()).get(CanteensViewModel.class);
Run Code Online (Sandbox Code Playgroud)
还SavedStateHandleAndroidViewModelApplication考虑在您的 中接收 a作为参数,而不仅仅是.
如果你问我,显然删除ViewModelProviders.of()是一个 API 错误,但这就是我们现在所拥有的。
编辑:在提供的堆栈跟踪的帮助下,我终于可以弄清楚发生了什么。
Run Code Online (Sandbox Code Playgroud)at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
我们使用的NewInstanceFactory是默认值。默认有NewInstanceFactory什么作用?如果可用,它只调用无参数构造函数。
等等,什么?不是应该填写Applicationfor anAndroidViewModel吗?
理论上是的,只要你得到原始的 default ViewModelProvider.Factory,但这不是一个!
为什么不是可以填AndroidViewModel的那个?
看到这个提交
Run Code Online (Sandbox Code Playgroud)Add default ViewModel Factory interface Use a marker interface to allow instances of ViewModelStoreOwner, such as ComponentActivity and Fragment, to provide a default ViewModelProvider.Factory that can be used with a new, concise ViewModelProvider constructor. This updates ComponentActivity and Fragment to use that new API to provide an AndroidViewModelFactory by default. It updates the 'by viewModels' Kotlin extensions to use this default Factory if one isn't explicitly provided.
还
Run Code Online (Sandbox Code Playgroud)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()); + } +
而最重要的是
Run Code Online (Sandbox Code Playgroud)public ViewModelProvider(@NonNull ViewModelStoreOwner owner) { this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance()); }
这意味着如果ViewModelStoreOwner 实现HasDefaultViewModelProviderFactory.
理论上,ComponentActivity确实是一个HasDefaultViewModelProviderFactory; 并AppCompatActivity从ComponentActivity.
但是,在您的情况下,情况似乎并非如此。出于某种原因,您AppCompatActivity的不是HasDefaultViewModelProviderFactory.
我认为解决您的问题的方法是将 Lifecycle 更新到 2.2.0,并至少更新implementation 'androidx.core:core-ktx到1.2.0。(特别是至少 AndroidX-Activity 1.1.0 和 AndroidX-Fragment 1.2.0)。
| 归档时间: |
|
| 查看次数: |
6295 次 |
| 最近记录: |