【问题标题】:how to provide different handling function to the injected InfiniteScrollListener instance - in kotlin如何为注入的 InfiniteScrollListener 实例提供不同的处理功能 - 在 kotlin
【发布时间】:2018-02-11 17:26:00
【问题描述】:

这与 using Dagger2 to provide a type with params got error "cannot be provided without an @Provides-annotated method" mean

似乎我找到了解决方法(感谢@David Medenjak 解释错误),它可以工作,但不确定是否有更好的方法来做到这一点,特别是提供向注入的 InfiniteScrollListener 实例证明不同处理函数的灵活性.当前的解决方案是处理函数在 PresentorModule 中硬编码。为此,我认为这不是解决错误的真正解决方案

@javax.inject.Named("func") kotlin.jvm.functions.Function0<kotlin.Unit> cannot be provided without an @Provides-annotated method.

这是当前的解决方案:

带有ViewScope的子组件,现在它提供了LinearLayoutManager和InfiniteScrollListener,它们是这个范围的单线体

@ViewScope
@Subcomponent(modules = arrayOf(PresentorModule::class))
interface PresentorComponent {

    fun inject (fragment: ArticlesFragment)

    fun getPresenter(): Presentor

    fun getLinearLayoutManager(): LinearLayoutManager
    fun getInfiniteScrollListener(): InfiniteScrollListener

}

PresentorModule 提供了linearLayoutManager(依赖于该模块的当前上下文),以及依赖于presentor 和linearLayoutManager 的InfiniteScrollListener,带有hard coded implementation of the handling function

@Module
class PresentorModule {

    var mContext: Context
    var mPresentor: Presentor

    constructor(context: Context) {
        mContext = context
        mPresentor = Presentor() 
    }
    @Provides
    @ViewScope
    internal fun context(): Context {// not sure if it has to implement to provide this mContext
        return mContext
    }

    @Provides
    @ViewScope

    fun presentor() : Presentor {
      return mPresentor      
    }

    @Provides
    @ViewScope

    fun linearLayoutManager() : LinearLayoutManager {
        return LinearLayoutManager(mContext)
    }

    @Provides
    @ViewScope
    fun infiniteScrollListener() : InfiniteScrollListener {
        return InfiniteScrollListener(
            {
                presentor().pullDataFromRemoteServer()
            },
            linearLayoutManager())
    }

 // really would like to have the flexibility of letting the consumer provides the 
 // handling function to the InfiniteScrollListener instance,  
 // but don’t know how to do it, so have to hard code the handling function
 // in the provider of InfiniteScrollListener listed above

 //    @Provides
 //    @ViewScope
 //    fun infiniteScrollListener(func: () -> Unit, layoutManager: LinearLayoutManager) :     InfiniteScrollListener {
 //        return InfiniteScrollListener(func, layoutManager)
 //    }
}

InfiniteScrollListener类的定义,它接受一个处理函数,在onScrolled()中调用

class InfiniteScrollListener (val func: () -> Unit,
                          val layoutManager: LinearLayoutManager) : RecyclerView.OnScrollListener() {
    init{
    … …
}

override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
    super.onScrolled(recyclerView, dx, dy) 

    … …
    func()
    … …
}

presentorComponent的使用:

private lateinit var presentorComponent: PresentorComponent
var infiniteScrollListener: InfiniteScrollListener? = null

@Inject
lateinit var presentor: Presentor

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
    ……

   //use dagger to inject viewScope presentor
    if (MyApp.graph != null) {
        presentorComponent = MyApp.graph
            .addChildModle(PresentorModule(getActivity()))

        presentorComponent
            .inject(this)
    }
    return view
}


override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    articlesList!!.apply {
        setHasFixedSize(true)
        clearOnScrollListeners()

        infiniteScrollListener = presentorComponent.getInfiniteScrollListener()

// old non-injection way to instantiate the InfiniteScrollListener with
// a custom handling function passed in at this moment

//            infiniteScrollListener = InfiniteScrollListener(
//                    {
//                        presentor.pullDataFromRemoteServer()                   
//                    },
//                    linearLayout)

        addOnScrollListener(infiniteScrollListener)

我真的很想在注入时灵活地提供不同的处理功能 类 InfiniteScrollListener,

就像旧代码所做的那样:

infiniteScrollListener = InfiniteScrollListener(
    {
        presentor.pullDataFromRemoteServer()           
    },
    linearLayout)

而不是硬编码在

@Module
class PresentorModule {

… …
    @Provides
    @ViewScope
    fun infiniteScrollListener() : InfiniteScrollListener {
        return InfiniteScrollListener(
            {
                presentor()
            },
            linearLayoutManager())
    }

【问题讨论】:

    标签: android kotlin dagger-2


    【解决方案1】:

    如果我理解正确,您希望注入 InfiniteScrollListener 的类不知道 LinearLayoutManager,而是负责编写执行的代码?

    或者你可以注入你的 InfiniteScrollMethod 并给它一个函数的 setter 方法。

    class InfiniteScrollListener (val layoutManager: LinearLayoutManager) : ...
    
        var func: (() -> Unit)?=null
    
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy) 
            ...
            func()
            ...
         }
    }
    

    然后在你的视图中:

    infiniteOnScollListener.func = { code() }
    addOnScrollListener(infiniteScrollListener)
    

    另外附注:在您的 dagger 模块中,无需直接调用 @Provides 方法。例如。

        @Provides
        @ViewScope
        fun provideInfiniteScrollListener(presenter:Presenter,linearLayoutManager: LinearLayoutManager) : InfiniteScrollListener {
            return InfiniteScrollListener(
                {
                    presenter
                },
                linearLayoutManager)
        }
    

    Dagger 将负责提供提供方法的参数。

    此外,传递给 InfiniteScollListener {presentor()} 的函数除了在调用它时创建一个新的演示者之外不会做任何事情(如果你不知道,而且它不仅仅是为了找出你的解决方案)。

    编辑:我想我可能已经理解了你想要做什么:你希望监听器在你的演示者或其他东西上调用一个函数,而视图不知道代码?

    这个怎么样:

     @Provides
    @ViewScope
    fun provideInfiniteScrollListener(@Named("scrollFunc1") func:()->Unit,presenter:Presenter,linearLayoutManager: LinearLayoutManager) : InfiniteScrollListener {
        return InfiniteScrollListener(func,linearLayoutManager)
    }
    
    @Provides
    @Named("scrollFunc1")
    fun scrollFunc(presenter:Presenter):()->Unit{
       return { presenter.onScrolled() }
    }
    

    我认为我最困惑的是“为 InfiniteScrollListener 提供方法的不同实现”是什么意思。究竟谁是函数的提供者?

    【讨论】:

    • 感谢您的帮助! presentor() 是复制/粘贴错误,应该是 presentor().pullDataFromRemoteServer()。我的意思是在注入 InfiniteScrollListener 时,它应该有一种方法允许 InfiniteScrollListener 使用不同的“处理程序函数”(目前它是硬编码的 presentor().pullDataFromRemoteServer())。我猜您的 setter 解决方案可能会起作用,很快就会尝试您的解决方案。
    • 请注意,当您调用 presentor(). ... 时,您正在创建演示者的新实例。使用带有参数的方法来获取您通过 @provides 注释方法提供的 Presenter 实例
    • 我不确定我是否正确,在我看来,在 PresentorModule 中,presentor() 将始终返回在此模块的构造函数中实例化的现有 mPresentor。是否仍来自新实例?
    • 哦,是的,你的情况是正确的,这是真的。我认为您的 presentor() 方法正在创建一个新的演示者。但是不管presentor方法做了什么,带有参数的方法都可以工作,因为Dagger将尊重@Provides注释方法的范围。因此,无论它来自哪里,您总是会得到相同的演示者。所以你现在可以保持原样,保持简单。
    • 顺便说一句,@Provide fun scrollFunc(presenter:Presenter):()->Unit 解决方案是我尽量避免的。尽量不要对模块内的“处理函数”进行硬编码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-10
    • 1970-01-01
    • 2020-03-07
    • 1970-01-01
    • 2019-11-11
    相关资源
    最近更新 更多