我正在开发一个旧的 Android 项目。我对 Android 有一点了解,但我的重点是 iOS。所以也许我在这里错过了一些简单的东西。
问题: 主屏幕正在工作,但当需要重新创建时,应用程序崩溃。今天我在设置中触发它并更改位置权限。
错误:
FATAL EXCEPTION: main
Process: com.x.activities, PID: 16127
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.x.activities/com.x.ui.home.HomeActivity}: android.view.InflateException: Binary XML file line #23 in com.xxx.activities:layout/activity_homescreen: Binary XML file line #23 in com.x.activities:layout/activity_homescreen: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: android.view.InflateException: Binary XML file line #23 in com.x.activities:layout/activity_homescreen: Binary XML file line #23 in com.x.activities:layout/activity_homescreen: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #23 in com.x.activities:layout/activity_homescreen: Error inflating class fragment
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.x.ui.home.HomeViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:204)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:322)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:304)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:53)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:35)
at com.x.ui.homescreen.HomescreenFragment.getParentViewModel(HomescreenFragment.kt:47)
at com.x.ui.homescreen.HomescreenFragment.observeParentViewModel(HomescreenFragment.kt:130)
at com.x.ui.homescreen.HomescreenFragment.onViewCreated(HomescreenFragment.kt:96)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3128)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1433)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2977)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:2888)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3129)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1433)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2977)
2023-09-08 14:54:08.143 16127-16127 AndroidRuntime com.x.activities E at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:2888)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3129)
at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:394)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:260)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:142)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:136)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:248)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:227)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1081)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1009)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:973)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1135)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1096)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1138)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1096)
at android.view.LayoutInflater.inflate(LayoutInflater.java:694)
at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
at android.view.LayoutInflater.inflate(LayoutInflater.java:485)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:699)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:195)
at com.x.ui.home.HomeActivity.onCreate(HomeActivity.kt:133)
at android.app.Activity.performCreate(Activity.java:8595)
at android.app.Activity.performCreate(Activity.java:8573)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: java.lang.InstantiationException: java.lang.Class<com.x.ui.home.HomeViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:202)
... 61 more
主屏幕片段
class HomescreenFragment : BaseMvRxFragment() {
private val parentViewModel by homeViewModel() //line 47
@Inject
internal lateinit var viewModelFactory: HomescreenViewModel.Factory
private val viewModel: HomescreenViewModel by fragmentViewModel()
private val homescreenActionsController by lazy { HomescreenActionsController(requireActivity()) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//...
observeParentViewModel() //line 96
//...
}
private fun observeParentViewModel() =
parentViewModel.permissionRequestResult.observeEvent(viewLifecycleOwner) { //line 130
homescreenActionsController.onPermissionResult(it)
}
//...
}
首页活动
class HomeActivity : AppCompatActivity(), HomeCallbacks, UsingLocation {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NetComponent.instance.inject(this)
initDagger()
setContentView(R.layout.activity_homescreen) //line 133
///...
}
///...
}
HomeViewModel
class HomeViewModel @Inject constructor(
private val userInbox: UserInbox,
private val prefUserInfo: PrefUserInfo,
private val prefAppInfo: PrefAppInfo,
private val prefOrgInfo: PrefOrgInfo,
private val realmController: RealmController,
private val api: Api,
private val loginState: LoginState,
private val application: LiveSafeApplication,
private val initializers: AppInitializer
) : ViewModel(), PushJsonConsumer {
init {
NetComponent.instance.inject(this)
///...
}
companion object {
fun Fragment.homeViewModel() = activityViewModels<HomeViewModel>()
}
}
activity_homescreen.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/homescreen_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/nav_host_fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_main" /> //line 23
</FrameLayout>
///...
</androidx.constraintlayout.widget.ConstraintLayout>
我发现的一个建议是替换:
private val parentViewModel by homeViewModel()
与
@Inject
lateinit var viewModelFactory2: ViewModelProvider.Factory
private val parentViewModel: HomeViewModel by viewModels { viewModelFactory2 }
如果我这样做,应用程序将不再崩溃,但函数observeParentViewModel中的代码不会被调用,所以我认为我得到了一个不同的实例。
parentViewModel
仅在observeParentViewModel
函数中调用,因此如果我仍然可以调用homescreenActionsController.onPermissionResult,我可以使用不同的策略
其他建议是创建一个自定义工厂,以便能够拥有一个不带参数的
HomeViewModel
,但我不明白如何传递参数才能创建一个HomeViewModel
该项目未使用 Hilt,仅使用 Dagger。
要修复 Android 项目中的“类没有零参数构造函数”错误,这里有一个简化的推荐解决方案:
HomeViewModel
创建一个可以处理依赖注入的自定义 ViewModel Factory。class HomeViewModelFactory @Inject constructor(
// Inject your dependencies here
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(HomeViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return HomeViewModel(
// Pass the injected dependencies here
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
HomeViewModel
和 HomeViewModelFactory
所需的依赖项。@Module
class AppModule {
// Provide your dependencies here
}
HomescreenFragment
以将 ViewModel 与自定义工厂一起使用,以实现正确的依赖项注入。class HomescreenFragment : BaseMvRxFragment() {
@Inject
lateinit var viewModelFactory: HomeViewModelFactory
private val parentViewModel: HomeViewModel by viewModels { viewModelFactory }
// ...
}
通过执行这些步骤,您的应用程序应该不再崩溃,并且您将能够使用
parentViewModel
及其正确注入的依赖项。确保您的 Dagger 设置提供所需的依赖项。