如何使用Hilt向Fragment注入ViewBinding 消除onCreateView样板代码
问题解答
错误原因
- 首次注入报错:你将提供
AlbumListFragmentBinding的Module安装在了ActivityComponent中,ActivityComponent的作用域无法获取对应Fragment的实例,因此无法构造Binding对象抛出错误。 - 循环依赖报错:为Fragment添加
@Inject构造方法后,Hilt创建Fragment实例时需要先完成所有成员的注入工作,而构造Binding又要求先提供Fragment实例,二者相互依赖形成死循环。
推荐方案:使用Kotlin属性委托消除样板代码
不推荐通过Hilt注入ViewBinding,ViewBinding的生命周期和Fragment的View生命周期严格绑定,Hilt注入时机早于View创建,容易出现内存泄漏、空指针等问题。使用Kotlin属性委托是目前最成熟的低侵入式方案:
- 先封装通用ViewBinding委托工具:
import android.view.View import androidx.fragment.app.Fragment import androidx.viewbinding.ViewBinding import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty inline fun <reified T : ViewBinding> Fragment.viewBinding() = object : ReadOnlyProperty<Fragment, T> { private var binding: T? = null override fun getValue(thisRef: Fragment, property: KProperty<*>): T { // 已初始化直接返回 binding?.let { return it } // 利用ViewBinding的bind方法绑定已 inflate 的布局 val view = thisRef.requireView() return T::class.java.getMethod("bind", View::class.java) .invoke(null, view) as T .also { binding = it } } }
- Fragment中直接使用,不需要编写
onCreateView样板代码:
@AndroidEntryPoint class AlbumListFragment : Fragment(R.layout.album_list_fragment) { // 直接声明即可自动初始化 private val binding by viewBinding<AlbumListFragmentBinding>() // 后续业务代码直接调用binding即可 }
强制使用Hilt注入的实现方案(不推荐)
如果一定要用Hilt实现,需要将Module安装到FragmentComponent中,且需要为每个Fragment的Binding单独配置Provider方法,反而会增加更多样板代码,完全没有收益,因此不建议使用。
内容的提问来源于stack exchange,提问作者Yanay Hollander
相关产品推荐
相关产品推荐

