如何在 Koin 中正确创建 class 的实例?
How to create an instances of the class in Koin correctly?
我现在正在学习 Koin,这是我的麻烦。
当我尝试 运行 应用程序时,我收到此错误:
kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:15)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:16)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.coordinators.RadioStations.<init>(RadioStations.kt:130)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:46)
at org.koin.core.instance.SingleInstanceFactory$get.invoke(SingleInstanceFactory.kt:53)
at org.koin.core.instance.SingleInstanceFactory$get.invoke(SingleInstanceFactory.kt:51)
at org.koin.mp.KoinPlatformTools.synchronized(PlatformToolsJVM.kt:20)
at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:51)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:15)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:16)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.coordinators.RadioStations.<init>(RadioStations.kt:130)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:46)
at org.koin.core.instance.SingleInstanceFactory$get.invoke(SingleInstanceFactory.kt:53)
(是的,这是我的日志,消息的开头是 t运行,因为它有 13k 行)
此应用程序是用于收听白俄罗斯广播的流媒体应用程序。
我不知道如何创建实现接口的 ViewModel 的实例,我只需要这样做来将 MainFragment 上下文获取到我的 ApiImpl class (RadioStations):
RadioStations.kt
interface RadioStationsURLAPI {
fun start(url: String)
fun stop()
fun getURL(id: Int): String
}
class RadioStations : KoinComponent, RadioStationsURLAPI {
private val mp = MediaPlayer()
val context = get<MainFragment>()
private fun getRadioCultureURL(): String {
return URLs.radioCulture
}
private fun getRadioWorldURL(): String {
return URLs.radioWorld
}
private fun getRadioEnergyURL(): String {
return URLs.radioEnergy
}
private fun getRadioCenterURL(): String {
return URLs.radioCenter
}
private fun getRadioOneURL(): String {
return URLs.radioOne
}
private fun getRadioRadiusFmURL(): String {
return URLs.radioRadius
}
private fun getRadioCapitalURL(): String {
return URLs.radioCapital
}
private fun getRadioBelarusURL(): String {
return URLs.radioBelarus
}
private fun getRadioBelarusFmURL(): String {
return URLs.radioBelarusFM
}
private fun getRadioCityFmURL(): String {
return URLs.radioCityFM
}
private fun getRadioMogilevURL(): String {
return URLs.radioMogilev
}
private fun getRadioBaURL(): String {
return URLs.radioBA
}
private fun getRadioRocksURL(): String {
return URLs.radioRocks
}
override fun getURL(id: Int): String {
when (id) {
R.id.radio_item_culture -> return getRadioCultureURL()
R.id.radio_item_world -> return getRadioWorldURL()
R.id.radio_item_energy -> return getRadioEnergyURL()
R.id.radio_item_center -> return getRadioCenterURL()
R.id.radio_item_one -> return getRadioOneURL()
R.id.radio_item_radius -> return getRadioRadiusFmURL()
R.id.radio_item_capital -> return getRadioCapitalURL()
R.id.radio_item_belarus -> return getRadioBelarusURL()
R.id.radio_item_belarus_fm -> return getRadioBelarusFmURL()
R.id.radio_item_city_fm -> return getRadioCityFmURL()
R.id.radio_item_mogilev -> return getRadioMogilevURL()
R.id.radio_item_BA -> return getRadioBaURL()
R.id.radio_item_rocks -> return getRadioRocksURL()
else -> return ""
}
}
override fun start(url: String) {
val uri = Uri.parse(url)
println(uri)
mp.apply {
context.context?.let { setDataSource(it, uri) }
prepareAsync()
}
mp.start()
}
override fun stop() {
mp.stop()
}
}
所以这是我的 Modules.kt Koin
val appModule = module {
single { RadioStations() }
viewModel { MainViewModel(get()) }
factory<MainViewModelInterface> { MainViewModel(get()) }
fragment { MainFragment(get()) }
}
我的MainViewModule.kt
interface MainViewModelInterface {
val choosedRadio: BehaviorSubject<Int>
val recoverableError: PublishSubject<String?>
}
class MainViewModel(val radioStations: RadioStations): ViewModel(), MainViewModelInterface {
override val choosedRadio: BehaviorSubject<Int> = BehaviorSubject.create<Int>()
override val recoverableError: PublishSubject<String?> = PublishSubject.create<String?>()
init {
choosedRadio
.map {
radioStations.getURL(it)
}
.observeOn(Schedulers.newThread())
.doOnError {
recoverableError.onNext(it.localizedMessage)
}
.subscribe({
radioStations.start(it)
}, Timber::e)
}
}
还有我的MainFragment.kt
class MainFragment(val viewModel: MainViewModelInterface) : Fragment() {
private lateinit var toolbar: androidx.appcompat.widget.Toolbar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.toolbar_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_main, container, false)
// Inflate the layout for this fragment
toolbar = view.findViewById(R.id.radio_toolbar)
(requireActivity() as AppCompatActivity).setSupportActionBar(toolbar)
return view
}
override fun onResume() {
super.onResume()
toolbar.setOnMenuItemClickListener {
viewModel.choosedRadio.onNext(it.itemId)
true
}
viewModel.recoverableError
.subscribe {
Toast.makeText(this.context, it, Toast.LENGTH_LONG).show()
}
}
}
如何在 Modules.kt 中编写我的 classes 的实例?我已经阅读了 Koin 文档,但仍然不明白如何正确执行此操作。
您需要打破依赖关系图中的循环。
RadioStations
取决于 MainFragment
。 MainFragment
取决于 MainViewModelInterface
。它的实现 MainViewModel
取决于 RadioStations
。尝试在此图中创建对象会导致无限递归,直到 VM 耗尽堆栈 space。
不会为您调试所有代码,但我会先删除
val context = get<MainFragment>()
因为片段并不是真正的上下文,并且像这样将片段作为依赖项无论如何都是可疑的。考虑将 Context
作为参数传递给那些需要它的函数。
我现在正在学习 Koin,这是我的麻烦。 当我尝试 运行 应用程序时,我收到此错误:
kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:15)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:16)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.coordinators.RadioStations.<init>(RadioStations.kt:130)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:46)
at org.koin.core.instance.SingleInstanceFactory$get.invoke(SingleInstanceFactory.kt:53)
at org.koin.core.instance.SingleInstanceFactory$get.invoke(SingleInstanceFactory.kt:51)
at org.koin.mp.KoinPlatformTools.synchronized(PlatformToolsJVM.kt:20)
at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:51)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:15)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:23)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:16)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:254)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:241)
at org.koin.core.scope.Scope.get(Scope.kt:204)
at com.example.radioapp.coordinators.RadioStations.<init>(RadioStations.kt:130)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at com.example.radioapp.ModulesKt$appModule.invoke(Modules.kt:13)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:53)
at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:46)
at org.koin.core.instance.SingleInstanceFactory$get.invoke(SingleInstanceFactory.kt:53)
(是的,这是我的日志,消息的开头是 t运行,因为它有 13k 行)
此应用程序是用于收听白俄罗斯广播的流媒体应用程序。
我不知道如何创建实现接口的 ViewModel 的实例,我只需要这样做来将 MainFragment 上下文获取到我的 ApiImpl class (RadioStations):
RadioStations.kt
interface RadioStationsURLAPI {
fun start(url: String)
fun stop()
fun getURL(id: Int): String
}
class RadioStations : KoinComponent, RadioStationsURLAPI {
private val mp = MediaPlayer()
val context = get<MainFragment>()
private fun getRadioCultureURL(): String {
return URLs.radioCulture
}
private fun getRadioWorldURL(): String {
return URLs.radioWorld
}
private fun getRadioEnergyURL(): String {
return URLs.radioEnergy
}
private fun getRadioCenterURL(): String {
return URLs.radioCenter
}
private fun getRadioOneURL(): String {
return URLs.radioOne
}
private fun getRadioRadiusFmURL(): String {
return URLs.radioRadius
}
private fun getRadioCapitalURL(): String {
return URLs.radioCapital
}
private fun getRadioBelarusURL(): String {
return URLs.radioBelarus
}
private fun getRadioBelarusFmURL(): String {
return URLs.radioBelarusFM
}
private fun getRadioCityFmURL(): String {
return URLs.radioCityFM
}
private fun getRadioMogilevURL(): String {
return URLs.radioMogilev
}
private fun getRadioBaURL(): String {
return URLs.radioBA
}
private fun getRadioRocksURL(): String {
return URLs.radioRocks
}
override fun getURL(id: Int): String {
when (id) {
R.id.radio_item_culture -> return getRadioCultureURL()
R.id.radio_item_world -> return getRadioWorldURL()
R.id.radio_item_energy -> return getRadioEnergyURL()
R.id.radio_item_center -> return getRadioCenterURL()
R.id.radio_item_one -> return getRadioOneURL()
R.id.radio_item_radius -> return getRadioRadiusFmURL()
R.id.radio_item_capital -> return getRadioCapitalURL()
R.id.radio_item_belarus -> return getRadioBelarusURL()
R.id.radio_item_belarus_fm -> return getRadioBelarusFmURL()
R.id.radio_item_city_fm -> return getRadioCityFmURL()
R.id.radio_item_mogilev -> return getRadioMogilevURL()
R.id.radio_item_BA -> return getRadioBaURL()
R.id.radio_item_rocks -> return getRadioRocksURL()
else -> return ""
}
}
override fun start(url: String) {
val uri = Uri.parse(url)
println(uri)
mp.apply {
context.context?.let { setDataSource(it, uri) }
prepareAsync()
}
mp.start()
}
override fun stop() {
mp.stop()
}
}
所以这是我的 Modules.kt Koin
val appModule = module {
single { RadioStations() }
viewModel { MainViewModel(get()) }
factory<MainViewModelInterface> { MainViewModel(get()) }
fragment { MainFragment(get()) }
}
我的MainViewModule.kt
interface MainViewModelInterface {
val choosedRadio: BehaviorSubject<Int>
val recoverableError: PublishSubject<String?>
}
class MainViewModel(val radioStations: RadioStations): ViewModel(), MainViewModelInterface {
override val choosedRadio: BehaviorSubject<Int> = BehaviorSubject.create<Int>()
override val recoverableError: PublishSubject<String?> = PublishSubject.create<String?>()
init {
choosedRadio
.map {
radioStations.getURL(it)
}
.observeOn(Schedulers.newThread())
.doOnError {
recoverableError.onNext(it.localizedMessage)
}
.subscribe({
radioStations.start(it)
}, Timber::e)
}
}
还有我的MainFragment.kt
class MainFragment(val viewModel: MainViewModelInterface) : Fragment() {
private lateinit var toolbar: androidx.appcompat.widget.Toolbar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.toolbar_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_main, container, false)
// Inflate the layout for this fragment
toolbar = view.findViewById(R.id.radio_toolbar)
(requireActivity() as AppCompatActivity).setSupportActionBar(toolbar)
return view
}
override fun onResume() {
super.onResume()
toolbar.setOnMenuItemClickListener {
viewModel.choosedRadio.onNext(it.itemId)
true
}
viewModel.recoverableError
.subscribe {
Toast.makeText(this.context, it, Toast.LENGTH_LONG).show()
}
}
}
如何在 Modules.kt 中编写我的 classes 的实例?我已经阅读了 Koin 文档,但仍然不明白如何正确执行此操作。
您需要打破依赖关系图中的循环。
RadioStations
取决于 MainFragment
。 MainFragment
取决于 MainViewModelInterface
。它的实现 MainViewModel
取决于 RadioStations
。尝试在此图中创建对象会导致无限递归,直到 VM 耗尽堆栈 space。
不会为您调试所有代码,但我会先删除
val context = get<MainFragment>()
因为片段并不是真正的上下文,并且像这样将片段作为依赖项无论如何都是可疑的。考虑将 Context
作为参数传递给那些需要它的函数。