Dagger-Hilt @AndroidEntryPoint 不能与 BottomSheetDialogFragment() 一起使用。

5

我正在 BottomSheetDialogFragment() 中使用 ViewModel,因此必须使用 @AndroidEntryPoint 标记我的 BottomSheet。

@AndroidEntryPoint
class SearchAddressDialog : BottomSheetDialogFragment() {

    private val viewModel: MyAddressesViewModel by viewModels()
    
    ......
}

但是当我尝试构建我的项目时,它会给我这个错误:

Execution failed for task ':app:kaptDebugKotlin'.
> A failure occurred while executing 
org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask$KaptExecutionWorkAction
> java.lang.reflect.InvocationTargetException (no error message)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option 
to get more log output. Run with --scan to get full insights.

这是我使用 --stacktrace参数运行 的输出结果:

https://gist.github.com/javlonrahimov/95de968645cace1dfb6e425381f8014b

如果我删除 BottomSheetFragmen() 上方的 @AndroidEntryPoint,应用程序将构建并安装。但当我尝试打开底部菜单时,由于将我的 repository 注入 ViewModel,应用程序崩溃:

java.lang.RuntimeException: Cannot create an instance of class uz.unical.other.ui.my_addresses.view_model.MyAddressesViewModel
    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 uz.unical.other.ui.my_addresses.dialogs.SearchAddressDialog.getViewModel(SearchAddressDialog.kt:26)
    at uz.unical.other.ui.my_addresses.dialogs.SearchAddressDialog.onResume(SearchAddressDialog.kt:86)
    at androidx.fragment.app.Fragment.performResume(Fragment.java:3039)
    at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:607)
    at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:306)
    at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
    at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
    at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
    at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:246)
    at android.app.ActivityThread.main(ActivityThread.java:8528)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
 Caused by: java.lang.InstantiationException: java.lang.Class<uz.unical.other.ui.my_addresses.view_model.MyAddressesViewModel> 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$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 uz.unical.other.ui.my_addresses.dialogs.SearchAddressDialog.getViewModel(SearchAddressDialog.kt:26) 
    at uz.unical.other.ui.my_addresses.dialogs.SearchAddressDialog.onResume(SearchAddressDialog.kt:86) 
    at androidx.fragment.app.Fragment.performResume(Fragment.java:3039) 
    at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:607) 
    at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:306) 
    at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189) 
    at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100) 
    at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002) 
    at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524) 
    at android.os.Handler.handleCallback(Handler.java:938) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:246) 
    at android.app.ActivityThread.main(ActivityThread.java:8528) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130

@AndroidEntryPoint 在其他普通的 Fragment 上没有出现错误。

更新:

这是我的视图模型:

@HiltViewModel
class MyAddressesViewModel @Inject constructor(
   private val repository: AddressRepository,
   private val geocoderRepository: GeocoderRepository
) : ViewModel() {}

更新2:

我现在正在注释BottomSheetDialogFragment(),但是编译时出现了错误。

如果我更改了这个代码:

@AndroidEntryPoint
class SearchAddressDialog : BottomSheetDialogFragment(){

转换为这样

@AndroidEntryPoint
class SearchAddressDialog : Fragment() {

它的工作非常完美。

我是否可以在BottomSheetDialogFragment()上使用@AndroidEntryPoint进行注释?

更新3:

这是我的BottomSheetDialogFragment


我已经尝试了一次干净的构建,但是没有成功。 - Javlon
const val navigation_version = "2.3.5" - Javlon
@MarkKeen 是的,我有。 - Javlon
你在其他地方使用过下划线作为包名吗?目前你的包命名空间是:uz.unical.other.ui.my_addresses.view_model.MyAddressesViewModel - 试着将 my_addressesview_model 包名改成没有下划线的形式。 - Mark
我已经重命名了我的包,但是它没有起作用。仍然出现相同的错误。 - Javlon
显示剩余8条评论
4个回答

2

经过长时间的研究,我无法解决@AndroidEntryPoint问题。 因此,我想到了这个方法:我只需在构造函数中将我的ViewModel传递给BottomSheetDialogFragment。

class SearchAddressDialog(
    private val viewModel: MyAddressesViewModel
) : BottomSheetDialogFragment() {
    ........ 
}

我是这样打开对话框的:

val dialog = SearchAddressDialog(viewModel)
dialog.show(childFragmentManager, SearchAddressDialog.TAG)

我已经使用了当前片段的ViewModel。

1
如果你还没有使用FragmentFactory,我很确定你需要使用它。如果不是这样,请尝试旋转设备(创建配置更改)。我预计会抛出一个错误,因为FragmentManager不知道如何重新创建Fragment。 - Mark
1
是的,经过一些崩溃后,我已经实现了“FragmentFactory” :)。现在它完美地工作了。 - Javlon
1
我发现这个回答是最有帮助的! - abhijat_saxena
1
这个答案是不正确的。DialogFragments(就像任何Fragments一样)应该始终具有无参空构造函数,而且没有其他构造函数。解决方案是确保ViewModelProviderFactory是HiltViewModelProviderFactory。 - EpicPandaForce

0
@AndroidEntryPoint & @HiltViewModel

非常完美!

这是我的底部弹出窗口片段和视图模型。

@AndroidEntryPoint
class BottomSheetFragment : BottomSheetDialogFragment() {
    companion object {
        const val TAG = "BottomSheetFragment"
    }

    private val viewModel by viewModels<BottomSheetFragmentViewModel>()
    private var _binding: BottomSheetFragmentBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,): View {
        _binding = BottomSheetFragmentBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel.test()
    }
}

@HiltViewModel
class BottomSheetFragmentViewModel @Inject constructor(
    private val localData: LocalRepository,
    private val remoteData: RemoteRepository,
) : BaseViewModel() {

    fun test() {}
}

最后在另一个片段中打开它,如下所示:

BottomSheetFragment().show(childFragmentManager, BottomSheetFragment.TAG);

注意:使用dagger & hilt 2.41版本

希望这能有所帮助! 愉快地编码吧!


0
首先,我希望您已经在项目中添加了hilt-android-gradle-plugin
其次,早期的dagger-hilt存在继承依赖问题,但自2.28版本以来已经修复。您可以在此链接中查看更多详细信息。https://github.com/google/dagger/issues/1910 因此,在您的情况下,不需要将@AndroidEntryPoint添加到BottomSheetDialogFragment中,但是您是否尝试过这样做?它能够正常工作吗?
另外,请问您能否分享一下您的BottomSheetDialogFragment类?

是的,我的项目中有 hilt-android-gradle-plugin。至于 GitHub 的问题,它没有帮助。我已经更新了我的问题,包括我的 BottomSheetDialog。 - Javlon
从 logcat 来看,似乎不是 dagger 的问题。你的 Kotlin 版本和 dagger-hilt 版本是多少?另外,你使用的是哪个 Java 版本? - 0xAliHn
const val kotlin_version = "1.5.31" const val hilt_version = "2.38.1" 我正在使用Java 11。 - Javlon

0

你在 AddressRepositoryGeocoderRepository 类的构造函数上添加了 @Inject 注解吗?也许你忘记给你的 ViewModel 类的依赖对象的构造函数打注解了。因此,Hilt/Dagger 无法解析依赖树。

如果是这种情况,请给所有依赖类的构造函数打上 @Inject 注解,问题就会得到解决。


我已经检查了所有依赖对象,我认为一切都很好。我已经更新了我的问题。 - Javlon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接