In this Factory I need to fetch my data from an api using Retrofit and store the cache with room, my Repository rules this app! I have repository suspended functions that take care of getting my data and some that save/update data getting and saveing/updating require different values to function and I do not know (yet) how to configure it in Kodein I lack the experience to solve this and there is nothing I found in Stackoverflow to assist me.
I have tried to add both the variables ID:String and the edited entity (CampaignEntry) to the Definition, it complies but crash on running with
No binding found for bind<CampaignEditViewModelFactory>() with ? { String -> ? }
My main Application the bind() is crashing the Application
class MarketingApplication : Application(), KodeinAware {
override val kodein = Kodein.lazy {
import(androidXModule(this@MarketingApplication))
...
bind() from factory { id: String, campaignEntry: CampaignEntry ->
CampaignEditViewModelFactory(id, campaignEntry, instance()) }
...
My ViewModel - having to pass the variables id and campaignEntry that is consumed by different calls in one ViewModel might be the issue - but I cannot figure out the correct solution.
class CampaignEditViewModel(
private val id: String,
private val campaignEntry: CampaignEntry,
private val marketingRepository: MarketingRepository
) : ViewModel() {
val campaignToSave by lazyDeferred { marketingRepository.updateCampaign(campaignEntry) }
val campaignToEdit by lazyDeferred { marketingRepository.getCampaignById(id) }
}
my lazyDeferred for clarity
fun <T> lazyDeferred(block: suspend CoroutineScope.() -> T): Lazy<Deferred<T>> {
return lazy {
GlobalScope.async(start = CoroutineStart.LAZY) {
block.invoke(this)
}
}
}
The Repository snap
interface MarketingRepository {
...
suspend fun getCampaignById(campaignId: String): LiveData<CampaignEntry>
suspend fun updateCampaign(campaignEntry: CampaignEntry): LiveData<CampaignEntry>
...
I call the Viewmodel from my fragment like so
class CampaignEditFragment : ScopedFragment(), KodeinAware {
override val kodein by closestKodein()
private val viewModelFactoryInstanceFactory: ((String) -> CampaignEditViewModelFactory) by factory()
...
private fun bindUI() = launch {
val campaignVM = campaignEditViewModel.campaignToEdit.await()
...
btn_edit_save.setOnClickListener {it: View
saveCampaign(it)
...
private fun saveCampaign(it: View) = launch {
campaignEditViewModel.campaignToSave.await()
}
And then lastly the ScopedFragment
abstract class ScopedFragment : Fragment(), CoroutineScope {
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
If you need any more code - please ask
Since you are binding with 2 arguments, you need to use factory2
:
private val viewModelFactoryInstanceFactory: ((String, campaignEntry) -> CampaignEditViewModelFactory) by factory2()