You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HiltViewModel注入BaseApplication失败问题排查

问题描述

我有一个纯Java编写的遗留项目,当前需升级平台,引入Jetpack Compose与Hilt以支持Kotlin和依赖注入。

我创建了Kotlin类ComposeCompat处理Composable创建:

class ComposeCompat(private val app: Activity) {
    fun getListViewComposable(): ComposeView =
        app.findViewById<ComposeView>(R.id.compose_list).apply {
            setContent {
                val vm: ListViewModel = viewModel()
                ListView(vm)
            }
        }
}

在MainActivity中如下调用该类,可正常访问Composable与无依赖的ListViewModel:

private final ComposeCompat compose = new ComposeCompat(this);

protected void onCreate(Bundle savedInstanceState) {
  compose.getListViewComposable();
}

无依赖的HiltViewModel代码如下:

@HiltViewModel
class ListViewModel @Inject constructor() : ViewModel() {
    val state: MutableState<State> = mutableStateOf(State.Loading)

    fun getState() = state.toString()
}

对应的Composable可正常运行:

@Composable
fun ListView(vm: ListViewModel) {
    Log.d("viewModel", "ViewModel starting")
    Log.d("viewModel", vm.getState())
}

但当为ListViewModel注入BaseApplication后:

@HiltViewModel
class ListViewModel
@Inject constructor(private val app: BaseApplication) : ViewModel() {
    val state: MutableState<State> = mutableStateOf(State.Loading)

    fun getState() = state.toString()
}

出现如下错误:

Transmitting stack trace: java.lang.RuntimeException: Cannot create an instance of class com.example.compose.list_view.ListViewModel
                                                                                                        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:204)

我曾怀疑BaseApplication实现有问题,但另一个注入BaseApplication的DialFragmentViewModel在Java Fragment中可正常使用:

ViewModel代码:

@HiltViewModel
class DialFragmentViewModel
@Inject constructor(private val app: BaseApplication) : ViewModel() {
    fun onGetApplicationFunction() {
        app.isServiceRunning("com.example.Service")
    }
}

在Java Fragment中调用方式:

private final DialFragmentViewModel viewModel = new ViewModelProvider(this).get(DialFragmentViewModel.class);

请问问题出在哪里?是否是ComposeCompat无法获取BaseApplication作为依赖注入?


问题原因与解决方案

核心问题

Compose中默认的viewModel()方法没有关联Hilt的ViewModelFactory,导致Hilt无法为ViewModel注入依赖。而Java Fragment能正常工作,是因为Hilt已为标注了@AndroidEntryPoint的Fragment自动配置了对应的Factory。

具体解决步骤

  1. 为MainActivity添加Hilt注解
    确保你的MainActivity标注了@AndroidEntryPoint,让Hilt为其提供依赖注入支持:

    @AndroidEntryPoint
    public class MainActivity extends AppCompatActivity {
        private final ComposeCompat compose = new ComposeCompat(this);
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            compose.getListViewComposable();
        }
    }
    
  2. 替换Compose中的ViewModel获取方法
    将Compose中默认的viewModel()替换为Hilt提供的hiltViewModel(),该方法会自动关联Hilt的Factory,实现依赖注入:

    class ComposeCompat(private val app: Activity) {
        fun getListViewComposable(): ComposeView =
            app.findViewById<ComposeView>(R.id.compose_list).apply {
                setContent {
                    // 改用hiltViewModel()获取带依赖的ViewModel
                    val vm: ListViewModel = hiltViewModel()
                    ListView(vm)
                }
            }
    }
    
  3. 确认BaseApplication的Hilt配置
    确保你的BaseApplication已标注@HiltAndroidApp,这是Hilt初始化的必要条件:

    @HiltAndroidApp
    class BaseApplication : Application() {
        // 你的其他业务代码
    }
    

为什么Java Fragment能正常工作?

Hilt会为标注了@AndroidEntryPoint的Fragment自动注入自定义ViewModelProvider.Factory,当你调用new ViewModelProvider(this)时,实际使用的是Hilt提供的Factory,因此能正确创建带依赖的ViewModel。而Compose的默认viewModel()没有绑定这个Factory,必须显式使用hiltViewModel()触发Hilt的注入逻辑。

内容的提问来源于stack exchange,提问作者Chris Pi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 06:05:36