如何为注入的InfiniteScrollListener实例提供不同的处理函数 - 在kotlin中

时间:2018-02-11 17:26:00

标签: android kotlin dagger-2

这与此有关 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)

我真的希望在注入时具有提供不同处理功能的灵活性 class InfiniteScrollListener,

就像旧代码所做的那样:

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

而不是

中的硬编码
@Module
class PresentorModule {

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

1 个答案:

答案 0 :(得分:1)

如果我理解正确,你希望注入InfiniteScrollListener的Class不知道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)

另外还有一个注意事项:在你的匕首模块中,不需要直接调用@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”。实际上谁是func的提供者?