You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Kotlin中如何用Dagger2实现Adapter的依赖注入?

如何在Adapter中实现Dagger2注入

首先得明确:Adapter不像Activity/Fragment是由Android系统实例化并能被Dagger自动处理的组件,所以得手动处理依赖注入的时机,下面给你两种常用的解决方案:

方案一:构造函数传参(推荐,更符合依赖注入思想)

这种方式不需要修改你的Dagger Component,核心是把需要的依赖通过Adapter的构造函数传入,让Adapter的依赖完全由外部提供,既清晰又方便测试。

  1. 修改Adapter的构造函数
    ExpandableDraggableSwipeableAdapter里,把AccountType作为构造参数添加进去:

    class ExpandableDraggableSwipeableAdapter(
        private val accountType: AccountType,
        // 保留你原来需要的其他参数,比如数据源等
    ) : BaseExpandableListAdapter() {
        // ... 你的其他Adapter代码
    
        // 子视图点击时直接用传入的accountType做检查
        override fun onChildClick(
            parent: ExpandableListView?,
            v: View?,
            groupPosition: Int,
            childPosition: Int,
            id: Long
        ): Boolean {
            if (accountType.isAdmin()) {
                // 执行管理员专属操作
            } else {
                // 普通用户操作逻辑
            }
            return true
        }
    }
    
  2. 在Fragment/Activity中创建Adapter时传入依赖
    既然你的Fragment/Activity已经能正常注入依赖,直接从这里拿到AccountType传给Adapter就行:

    class YourHostFragment : Fragment() {
        // 先在Fragment中注入AccountType
        @Inject lateinit var accountType: AccountType
    
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            // ... 初始化视图逻辑
            val adapter = ExpandableDraggableSwipeableAdapter(accountType, yourDataSource)
            expandableListView.setAdapter(adapter)
            return view
        }
    }
    

方案二:通过Dagger Component手动注入(适合复杂场景)

如果你坚持要用Dagger的inject方法来注入,关键是要保证在Adapter使用依赖之前完成注入操作,不能等到Adapter的生命周期方法里才处理。

  1. 确认Component的inject方法定义正确
    你现有的ActivityComponent定义没问题,继续保留:

    interface ActivityComponent : BaseComponent {
        fun inject(expDragSwipeAdapter: ExpandableDraggableSwipeableAdapter)
    }
    
  2. 在Adapter中添加待注入的成员变量
    @Inject标注需要注入的变量,注意不要设为private(或者用@JvmField标注):

    class ExpandableDraggableSwipeableAdapter : BaseExpandableListAdapter() {
        @Inject lateinit var accountType: AccountType
    
        // ... 其他Adapter代码
    
        override fun onChildClick(...) : Boolean {
            // 这里就能正常使用accountType了
            return true
        }
    }
    
  3. 在Fragment/Activity中创建Adapter后立即调用注入
    必须在Adapter绑定到ListView之前,调用Component的inject方法完成注入:

    class YourHostFragment : Fragment() {
        // 注入ActivityComponent(或者从宿主Activity中获取)
        @Inject lateinit var activityComponent: ActivityComponent
    
        override fun onCreateView(...) : View? {
            // ... 初始化视图
            val adapter = ExpandableDraggableSwipeableAdapter()
            // 关键:创建Adapter后立刻注入!
            activityComponent.inject(adapter)
            expandableListView.setAdapter(adapter)
            return view
        }
    }
    

为什么之前注入对象为空?

你之前遇到的问题,大概率是因为在Adapter的onCreate方法里才尝试注入——这时候Adapter已经被系统初始化并绑定到视图了,而且Dagger的inject方法根本没被调用(或者调用时机太晚),导致accountType一直处于未初始化状态。记住:Dagger不会自动注入非Android系统组件,必须手动调用inject方法,且要在使用依赖之前完成

总的来说,方案一更推荐,它让Adapter的依赖关系更透明,单元测试时还能轻松传入Mock的AccountType

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

火山引擎 最新活动