Hello Kodein. I hope all is well and that you and ...
# kodein
m
Hello Kodein. I hope all is well and that you and your family are safe & healthy during this time. I'm learning Kodein now, and writing a test project with it, for an excellent job interview. Since the last day, I had an error, not solved yet. This is the error: org.kodein.di.Kodein$NotFoundException: No binding found for bind<ForecastRepositoryImpl>() with ?<ForecastFragment>().? { ? } Could you please help me with this? Taking this job is vital to me. Thanks a lot.
j
Make sure you are actually doing the binding
and if you are including another module, make sure you surround it with import(...) (I usually forget that)
perhaps paste your code here
because in my experience, if it tells me there is no binding found then I always messed up and didn't provide the proper binding
r
how do you retrieve
ForecastRepositoryImpl
in
ForecastFragment
. do you use some custom context?
m
@Joost Klitsie
Copy code
class ForecastApplication : Application(), KodeinAware {
    override val kodein = Kodein.lazy {
        import(androidXModule(this@ForecastApplication))

        bind() from provider { LocationServices.getFusedLocationProviderClient(instance<Context>()) }
        
        bind<Double>() with singleton { instance<ForecastRepositoryImpl>().latitude; instance<ForecastRepositoryImpl>().longitude }

        bind() from singleton { ForecastDatabase(instance()) }
        bind() from singleton { instance<ForecastDatabase>().forecastDao() }
        bind<ConnectivityInterceptor>() with singleton { ConnectivityInterceptorImpl(instance()) }
        bind() from singleton { ForecastApiService(instance()) }
        bind<ForecastNetworkDataSource>() with singleton { ForecastNetworkDataSourceImpl(instance()) }
        bind<ForecastRepository>() with singleton { ForecastRepositoryImpl(instance(), instance(),instance(), instance()) }
        bind() from provider { ForecastViewModelFactory(instance()) }
    }

    override fun onCreate() {
        super.onCreate()
        AndroidThreeTen.init(this)
    }
}
@Joost Klitsie I cant find how to bind ForecastRepositoryImpl with ForecastFragment
@romainbsl This line is in `ForecastFragment`:
Copy code
viewModel = ViewModelProvider(this, viewModelFactory).get(ForecastViewModel::class.java)
This is
ForecastViewModel
class:
Copy code
class ForecastViewModel(
    private val forecastRepository: ForecastRepository
) : ViewModel() {

    val forecast by lazyDeferred {
        forecastRepository.getForecast(10.0, 10.0)
    }
}
The `ForecastRepository`:
Copy code
interface ForecastRepository {
    suspend fun getForecast(lat: Double, lon: Double): LiveData<out Forecast>
}
And finally `ForecastRepositoryImpl`:
Copy code
class ForecastRepositoryImpl(
    private val forecastDao: ForecastDao,
    private val forecastNetworkDataSource: ForecastNetworkDataSource,
    internal val latitude: Double,
    internal val longitude: Double
) : ForecastRepository {
---
}
j
perhaps this is wrong:
Copy code
bind<Double>() with singleton { instance<ForecastRepositoryImpl>().latitude; instance<ForecastRepositoryImpl>().longitude }
You should use
instance<ForecastRepository>
instead of the
Impl
one. With
bind<SomeClass>
in other places you can only find the
SomeClass
and not the
SomeClassImpl
that you were binding it to.
also I am confused with this line:
Copy code
bind<Double>() with singleton { instance<ForecastRepositoryImpl>().latitude; instance<ForecastRepositoryImpl>().longitude }
what do you try to achieve here?
you are binding a Double instance to the return of this function, which is
instance<ForecastRepositoryImpl>().longitude
(because whatever you put before and divided with the ';' is ignored here) Also after that you are trying to inject this double what you get from the ForecastRepositoryImpl into the constructor of the ForecastRepositoryImpl creating a loop. You never even pass a value to this double so how would kodein have to figure out what the latitude and longitude values are?
Are you sure you want to inject a lat long to your repository if you also pass the lat long to the function call?
I guess what happens: you try to inject a double into a the repository implementation. The binding to that double is wrong as it relies on a non-existing binding
so I'd say: get rid of this:
Copy code
class ForecastRepositoryImpl(
    private val forecastDao: ForecastDao,
    private val forecastNetworkDataSource: ForecastNetworkDataSource,
    // --> internal val latitude: Double, // <-- not necessary
    // --> internal val longitude: Double // <-- not necessary
) : ForecastRepository {
---
}
If you really need these, then either inject them with Named arguments or with a multiton
but I am guessing you don't need them
m
That
bind<Double>
was because of this latest error:
org.kodein.di.Kodein$NotFoundException: No binding found for bind<Double>() with ? { ? }
,after this error I added that.
I cant use 
instance<ForecastRepository>
 instead of the 
Impl
 one, because of this syntax error:
Type inference failed. Expected type mismatch:
required:KodeinBinding<in Any?, in Unit, out Double>
found:Singleton<Any?, Nothing?, ForecastRepository>
j
Yes so remove those two doubles from you forecastrepository constructor
Can you try that?
Like why are you injecting those two doubles?
m
OK, I commented all about those two doubles, and the errors gone. So now, how can I pass latitude and longitude values to the API?
@Joost Klitsie could you please read this and help me if you can? https://kotlinlang.slack.com/archives/C7KS458SJ/p1605463513019600
j
I cannot say, try to put a breakpoint there and debug why the
value
is null
Btw, if you wanna pass latitude and longitude to the api, you usually do a method call, lets say a fake method name:
Copy code
fun loadAtCoordinates(latitude: Double, longitude: Double) {
    // ...
}
I think in your interface:
Copy code
interface ForecastRepository {
    suspend fun getForecast(lat: Double, lon: Double): LiveData<out Forecast>
}
this is defined, so no need to also pass in the lat and lon into the constructor