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

Hilt注入Leanback Presenter时lateinit属性未初始化问题

问题根因

这个问题和Leanback库本身无关,是Hilt注入的触发逻辑没生效:

  • Hilt中被@Inject标注的lateinit字段不会自动完成初始化,只有两种场景会触发字段注入:一是类的实例完全由Hilt创建管理;二是你主动将手动创建的实例传给Hilt,显式触发注入流程。
  • 你的ShowCardPresenter及其子类是手动通过构造函数new出来的,Hilt根本感知不到这个实例的存在,自然不会为你注入settings、detailsRepository字段,调用时必然抛出未初始化异常。
可行解决方案

二选一即可,优先推荐第二种,更符合Hilt的设计规范。

方案1:手动触发已有实例的注入

如果暂时不想调整现有构造逻辑,可以在创建Presenter实例的位置(通常是承载Leanback组件的Activity/Fragment,属于Hilt支持的入口类),主动调用Hilt的注入接口完成字段赋值。

  1. 先定义注入入口点,指定作用域在Fragment/Activity组件上:
@EntryPoint
@InstallIn(FragmentComponent::class)
interface PresenterInjectEntryPoint {
    fun inject(presenter: ShowCardPresenter)
}
  1. 在你new出LiveShowCardPresenter实例后,立刻执行注入,之后再使用实例:
val presenter = LiveShowCardPresenter(requireContext(), listener, hasVariableWidth)
// 显式触发注入
val entryPoint = EntryPointAccessors.fromFragment(this, PresenterInjectEntryPoint::class.java)
entryPoint.inject(presenter)
// 后续再把presenter设置给Adapter等组件

注意:所有继承自ShowCardPresenter的子类实例,都必须走一遍这个注入流程,否则还是会出现字段未初始化的问题。

方案2:改用构造注入(推荐)

把依赖直接声明在类的构造参数中,让Hilt负责依赖的装配,从根源上避免忘记触发注入的问题。如果Presenter存在运行时才传入的自定义参数(比如你的listener、hasVariableWidth),配合@AssistedInject实现带自定义参数的注入即可。

  1. 首先改造抽象父类ShowCardPresenter,把需要的依赖放到构造参数中,去掉原来的字段注入声明:
abstract class ShowCardPresenter @Inject constructor(
    val context: Context,
    var listener: ShowCardViewListener?,
    val settings: BackendSettings,
    val detailsRepository: DetailsRepository
) : Presenter() {
    // 删掉原来的@Inject lateinit var settings/detailsRepository 声明
}
  1. 改造子类LiveShowCardPresenter,用@AssistedInject标注构造,运行时传入的自定义参数加@Assisted注解,同时定义对应的辅助注入工厂:
class LiveShowCardPresenter @AssistedInject constructor(
    context: Context,
    @Assisted listener: ShowCardViewListener,
    @Assisted val hasVariableWidth: Boolean = false,
    settings: BackendSettings,
    detailsRepository: DetailsRepository
) : ShowCardPresenter(context, listener, settings, detailsRepository) {

    @AssistedFactory
    interface Factory {
        fun create(listener: ShowCardViewListener, hasVariableWidth: Boolean): LiveShowCardPresenter
    }

    override fun onCreateViewHolder(parent: ViewGroup): ViewHolder {
        val viewholder = ViewHolder(LiveShowCardView(context, hasVariableWidth))
        // 这里settings已经通过构造传入,可直接调用,不会触发未初始化异常
        viewholder.prepareViewHolderForeground(context, settings.isATV)
        return viewholder
    }
}
  1. 在使用Presenter的Activity/Fragment中,直接注入工厂实例,通过工厂创建Presenter即可,不需要手动处理注入逻辑:
@AndroidEntryPoint
class LiveShowFragment : BrowseSupportFragment() {
    @Inject
    lateinit var cardPresenterFactory: LiveShowCardPresenter.Factory

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 通过工厂创建实例,所有依赖已自动装配完成
        val cardPresenter = cardPresenterFactory.create(showCardListener, hasVariableWidth = false)
        // 后续将presenter设置给ObjectAdapter即可
    }
}

补充:Leanback的ObjectAdapter本身不会主动和Hilt联动,如果你直接把Presenter的Class传给Adapter让框架反射创建实例,Hilt同样无法感知实例创建过程,必须通过上述两种方式手动完成注入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:54:27