Reputation: 8670
I am having a shared View Model for activity and it's fragment.
My view model need's argument to be passed when instantiating from the activity(onCreate
only once)
viewModel =ViewModelProviders.of(this,
NoteViewModelFactory(application!!,
uid = intent!!.getStringExtra("uid")!!))
.get(NoteViewModel::class.java)
But from fragment i don't need to pass the argument as i am sure the i have the argument's passed once.
viewModel = ViewModelProviders.of(activity!!).get(NoteViewModel::class.java)
In Koin
i tried doing below.
val noteModule = module(override = true) {
viewModel { (id: String) -> NoteViewModel(androidApplication(), id) }
}
in Activity:
private val viewModel: NoteViewModel by viewModel { parametersOf(intent!!.getStringExtra("uid")!!) }
in Fragment:
private val viewModel: NoteViewModel by sharedViewModel()
Application Crashed with below error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.andor.navigate.notepad/com.andor.navigate.notepad.listing.NotesActivity}: org.koin.core.error.InstanceCreationException: Could not create instance for [type:Factory,primary_type:'com.andor.navigate.notepad.core.NoteViewModel'] at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [type:Factory,primary_type:'com.andor.navigate.notepad.core.NoteViewModel'] at org.koin.core.instance.DefinitionInstance.create(DefinitionInstance.kt:61) at org.koin.core.instance.FactoryDefinitionInstance.get(FactoryDefinitionInstance.kt:37) at org.koin.core.definition.BeanDefinition.resolveInstance(BeanDefinition.kt:70) at org.koin.core.scope.Scope.resolveInstance(Scope.kt:165)
I am not able to understand how to solve this using KOIN.
P.S:i am new to koin DI.
Upvotes: 3
Views: 12395
Reputation: 6373
You shouldn't pass these type of arguments in ViewModel
constructor. Instead what you can do is on your Activity's onCreate()
, you set that passed value to the ViewModel
. So when you will access that ViewModel
in your fragment, you'll surely have that value already set.
class NoteViewModel (application: Application) : AndroidViewModel(application)
{
var id:String = ""
}
Your koin Module:
val noteModule = module(override = true) {
viewModel { NoteViewModel(androidApplication()) }
}
Activity:
class MainActivity : AppCompatActivity() {
private val viewModel: NoteViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.id = intent?.getStringExtra("uid")?: ""
supportFragmentManager.beginTransaction().replace(R.id.container, MyFrag()).commit()
}
}
Fragment:
class MyFrag : Fragment() {
private val viewModel: NoteViewModel by sharedViewModel()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// your value will be available here.
return inflater.inflate(R.layout.activity_main, container, false)
}
}
Upvotes: 0
Reputation: 939
Is there anything wrong when you init koin in application class? I tried your code without any issuses. I'm using koin version 2.0.1
class App : Application() {
override fun onCreate() {
super.onCreate()
val noteModule = module(override = true) {
viewModel { (id: String) -> NoteViewModel(androidApplication(), id) }
}
startKoin {
androidContext(this@App)
modules(
noteModule
)
}
}
}
Activity and fragment:
class MainActivity : AppCompatActivity() {
private val viewModel: NoteViewModel by viewModel { parametersOf(intent!!.getStringExtra("uid")) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d("NoteViewModel", "id: ${viewModel.id}")
supportFragmentManager.beginTransaction().replace(R.id.main_root, Frag()).commit()
}
}
class Frag : Fragment() {
private val viewModel: NoteViewModel by sharedViewModel()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
Log.d("NoteViewModel", "id: ${viewModel.id}")
return inflater.inflate(R.layout.activity_main, container, false)
}
}
View model class:
class NoteViewModel (application: Application, val id: String) : AndroidViewModel(application)
Upvotes: 0