This is related to using Dagger2 to provide a type with params got error "cannot be provided without an @Provides-annotated method" mean
Seems I find a work around (thanks @David Medenjak for explain the error), it works, but not sure if there is better way to do it, especially to provide the flexibility of proving different handling function to the injected InfiniteScrollListener instance. Current solution the handling function is hard coded in the PresentorModule. For that I don't think it is a really solution for the error of
@javax.inject.Named("func") kotlin.jvm.functions.Function0<kotlin.Unit> cannot be provided without an @Provides-annotated method.
Here is the current solution:
The subcomponent with ViewScope, now it provides LinearLayoutManager and InfiniteScrollListenerwhich are singlets to this scope
@ViewScope
@Subcomponent(modules = arrayOf(PresentorModule::class))
interface PresentorComponent {
fun inject (fragment: ArticlesFragment)
fun getPresenter(): Presentor
fun getLinearLayoutManager(): LinearLayoutManager
fun getInfiniteScrollListener(): InfiniteScrollListener
}
The PresentorModule provides linearLayoutManager (has dependency on the current context of this module), and InfiniteScrollListener which depends on the presentor and the linearLayoutManager, with a 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)
// }
}
The definition of InfiniteScrollListener class, which takes a handling function and it is called in 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()
… …
}
The use of 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)
I really would like to have the flexibility of provide different handling function when inject the class InfiniteScrollListener,
Like the old code was doing:
infiniteScrollListener = InfiniteScrollListener(
{
presentor.pullDataFromRemoteServer()
},
linearLayout)
Instead of hardcoded in the
@Module
class PresentorModule {
… …
@Provides
@ViewScope
fun infiniteScrollListener() : InfiniteScrollListener {
return InfiniteScrollListener(
{
presentor()
},
linearLayoutManager())
}