While I am trying to handle Process Death in my Android Application, I noticed that the ViewModel which was scoped to the navigation Graph was crashing while recreating from the process death. Below is the code of the ViewModel and the Fragment which is using the ViewModel.
@ExperimentalCoroutinesApi
@HiltViewModel
class ViewPrintOrderVM @Inject constructor(
private val repository: Repository,
private val application: Application,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// Code inside the ViewModel
}
And in my Fragment, I am getting the reference as follows
@ExperimentalComposeUiApi
@ExperimentalCoroutinesApi
@AndroidEntryPoint
class ComposeFragmentPostPressDetails : Fragment() {
//Here we are scoping the ViewModel to the Navigation graph with graph-id instead of this fragment
private val viewModel: ManagePrintOrderVM by navGraphViewModels(R.id.print_order_flow)
//Rest of the Fragment code
}
Now, when I try to test the app for process death by launching the app in the emulator, putting it in the background, and then killing the process with the "Terminate Application" button from the android studio, it crashes while recreating with the following error
2022-03-19 19:06:44.633 7174-7174/com.sivakasi.papco.jobflow E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sivakasi.papco.jobflow, PID: 7174
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sivakasi.papco.jobflow/com.sivakasi.papco.jobflow.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.sivakasi.papco.jobflow.screens.manageprintorder.ManagePrintOrderVM
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.sivakasi.papco.jobflow.screens.manageprintorder.ManagePrintOrderVM
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
at com.sivakasi.papco.jobflow.screens.manageprintorder.FragmentPaperDetails.getViewModel(FragmentPaperDetails.kt:42)
at com.sivakasi.papco.jobflow.screens.manageprintorder.FragmentPaperDetails.observeViewModel(FragmentPaperDetails.kt:97)
at com.sivakasi.papco.jobflow.screens.manageprintorder.FragmentPaperDetails.onViewCreated(FragmentPaperDetails.kt:59)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1333)
at android.app.Activity.performStart(Activity.java:6992)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.InstantiationException: java.lang.Class<com.sivakasi.papco.jobflow.screens.manageprintorder.ManagePrintOrderVM> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
However, all other screens where the ViewModel is scoped just to that Fragment instead of scoping it to the navigation graph are working fine on Process recreation even with dependency injection.
What am I doing wrong? What should I do to handle Process death in a flow? How to handle process recreation in the fragments where the ViewModel is scoped to the Navigation Graph instead of the fragment itself or the Activity?
by navGraphViewModels
knows nothing about your Hilt factory - it is just using the default factory. The only reason it may work in other cases is because another fragment that did use Hilt's factory had created the ViewModel first.
As per the documentation, you must use by hiltNavGraphViewModels()
to use a Hilt injected ViewModel scoped to a navigation graph.
// Add this to your dependencies
implementation 'androidx.hilt:hilt-navigation-fragment:1.0.0'
// Then use it in place of navGraphViewModels()
private val viewModel: ManagePrintOrderVM by hiltNavGraphViewModels(R.id.print_order_flow)