I've been struggling on this the whole day and still can't make it work. In an existing Single Activity app, I'm trying to replace all fragment transactions by implementing the Navigation component
.
I've already created a Navigation graph and included the FragmentContainerView
as a child of the root ViewGroup
as it was proposed in the official docs.
activity_main.xml
<FrameLayout
android:id="@+id/container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBarLayout">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/main_content"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBarLayout"
app:navGraph="@navigation/nav_graph" />
</FrameLayout>
Now the problem that I'm currently facing is that the SharedViewModel
which I am using through the whole app can't be instantiated in the BaseFragment
anymore.
BaseFragment.kt
abstract class BaseFragment<E : ViewDataBinding, T : BaseViewModel> : Fragment() {
lateinit var viewModel: T
lateinit var dataBinding: E
abstract fun getLayoutResource(): Int
abstract fun getViewModelClass(): Class<T>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.let {
// java.lang.RuntimeException: Cannot create an instance of class SharedViewModel
viewModel = ViewModelProvider(it).get(getViewModelClass())
// viewModel = ViewModelProvider(getParentFragment()).get(getViewModelClass()) also doesn't work
}
}
...
}
BaseViewModel.kt
abstract class BaseViewModel : ViewModel(), LifecycleObserver
SharedViewModel.kt
abstract class SharedViewModel : BaseViewModel() {
...
}
SharedViewModelImpl.kt
class SharedViewModelImpl(private val repository: AppRepository) : SharedViewModel(){
...
}
I've read posts on SO and as well as Medium articles that recommend creating the SharedViewModel
by using by navGraphViewModels
like this
val viewModel: SharedViewModel by navGraphViewModels(R.id.navigation_graph)
but it seems that I still can't combine this approach with the generics that I already have.
My assumption is that the Navigation component
can't deal with abstract
classes.
How can I overcome this problem by keeping my existing app architecture? Many thanks in advance.
UPDATE:
@ianhanniballake asked me to post the entire stack trace. So here it is:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: at.bwappsandmore.doitagain, PID: 13528
java.lang.RuntimeException: Unable to start activity ComponentInfo{at.bwappsandmore.doitagain/at.bwappsandmore.doitagain.ui.MainActivity}: android.view.InflateException: Binary XML file line #44: Binary XML file line #44: Error inflating class androidx.fragment.app.FragmentContainerView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.view.InflateException: Binary XML file line #44: Binary XML file line #44: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: android.view.InflateException: Binary XML file line #44: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: java.lang.RuntimeException: Cannot create an instance of class at.bwappsandmore.doitagain.viewModel.SharedViewModel
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:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at at.bwappsandmore.doitagain.base.BaseFragment.onCreate(BaseFragment.kt:31)
at at.bwappsandmore.doitagain.ui.DisplayDataFragment.onCreate(DisplayDataFragment.kt:85)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2684)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:280)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1175)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2629)
at androidx.fragment.app.FragmentManager.dispatchCreate(FragmentManager.java:2571)
at androidx.fragment.app.Fragment.onCreate(Fragment.java:1685)
at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.java:264)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2684)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:280)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1175)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303)
at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.java:166)
E/AndroidRuntime: at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:51)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:356)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:335)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:696)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:170)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:303)
at androidx.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:284)
at at.bwappsandmore.doitagain.base.BaseActivity.onCreate(BaseActivity.kt:27)
at at.bwappsandmore.doitagain.ui.MainActivity.onCreate(MainActivity.kt:46)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.InstantiationException: java.lang.Class<at.bwappsandmore.doitagain.viewModel.SharedViewModel> cannot be instantiated
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
... 60 more
question from:
https://stackoverflow.com/questions/65847588/how-to-scope-the-sharedviewmodel-after-migrating-an-existing-app-to-use-the-navi 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…