org.koin.core.error.InstanceCreationException: 无法为 [Factory:'com.pokemonsearch.presentation.search.SearchViewModel'] 创建实例

org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.pokemonsearch.presentation.search.SearchViewModel']

我在我的 Kotlin 应用程序中使用 Koin 作为依赖注入框架。我正在尝试使用协程将数据保存到 Room 数据库。我有一个从视图模型调用的用例“AddToFavourite”class。 运行 应用程序崩溃并出现以下错误。当我检查时,我明白 koin 找不到一些依赖项。谁能帮我解决一个问题。请找到以下存储库、用例、视图模型、数据库和 di 模块

Process: com.debin.pokemonsearch, PID: 16027
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.debin.pokemonsearch/com.debin.pokemonsearch.HomeActivity}: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.debin.pokemonsearch.presentation.search.SearchViewModel']
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817`
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
     Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.debin.pokemonsearch.presentation.search.SearchViewModel']
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
        at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
        at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        at org.koin.core.scope.Scope.get(Scope.kt:181)
        at org.koin.android.viewmodel.ViewModelFactoryKt$defaultViewModelFactory.create(ViewModelFactory.kt:13)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at org.koin.android.viewmodel.ViewModelResolutionKt.get(ViewModelResolution.kt:21)
        at org.koin.android.viewmodel.ViewModelResolutionKt.resolveInstance(ViewModelResolution.kt:10)
        at org.koin.android.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:68)
        at org.koin.android.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:56)
        at org.koin.android.viewmodel.koin.KoinExtKt.getViewModel(KoinExt.kt:34)
        at org.koin.android.viewmodel.ext.android.ViewModelStoreOwnerExtKt.getViewModel(ViewModelStoreOwnerExt.kt:66)
        at com.debin.pokemonsearch.presentation.search.SearchFragment$$special$$inlined$viewModel.invoke(ViewModelStoreOwnerExt.kt:71)
        at com.debin.pokemonsearch.presentation.search.SearchFragment$$special$$inlined$viewModel.invoke(Unknown Source:0)
        at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)
        at com.debin.pokemonsearch.presentation.search.SearchFragment.getViewModel(Unknown Source:2)
        at com.debin.pokemonsearch.presentation.search.SearchFragment.observePokemon(SearchFragment.kt:39)
        at com.debin.pokemonsearch.presentation.search.SearchFragment.onViewCreated(SearchFragment.kt:31)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:332)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2625)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577)
        at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2722)
        at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:346)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1188)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
2021-01-24 19:49:54.088 16027-16027/com.debin.pokemonsearch E/AndroidRuntime:     at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2625)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1333)
        at android.app.Activity.performStart(Activity.java:6992)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
            ... 9 more
     Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.debin.pokemonsearch.pokemoncore.interactors.AddToFavourites']
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
        at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
        at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        at org.koin.core.scope.Scope.get(Scope.kt:181)
        at com.debin.pokemonsearch.di.ViewModelModuleKt$viewModelModule.invoke(ViewModelModule.kt:24)
        at com.debin.pokemonsearch.di.ViewModelModuleKt$viewModelModule.invoke(Unknown Source:4)
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
            ... 49 more
     Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Single:'com.debin.pokemonsearch.pokemoncore.domain.repository.IPokemonCoreRepository']
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
        at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:40)
        at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:48)
        at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        at org.koin.core.scope.Scope.get(Scope.kt:181)
        at com.debin.pokemonsearch.di.UseCaseModuleKt$useCaseModule.invoke(UseCaseModule.kt:23)
        at com.debin.pokemonsearch.di.UseCaseModuleKt$useCaseModule.invoke(Unknown Source:4)
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
            ... 56 more
     Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Single:'com.debin.pokemonsearch.pokemoncore.data.datasource.PokemonCoreDataSource']
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
        at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:40)
        at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:48)
        at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
        at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
        at org.koin.core.scope.Scope.get(Scope.kt:181)
        at com.debin.pokemonsearch.di.RepositoryModuleKt$repositoryModule.invoke(RepositoryModule.kt:19)
        at com.debin.pokemonsearch.di.RepositoryModuleKt$repositoryModule.invoke(Unknown Source:4)
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
            ... 64 more
     Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'com.debin.pokemonsearch.framework.db.PokemonDatabase'. Check your definitions!
        at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:246)
        at org.koin.core.scope.Scope.resolveInstance(Scope.kt:216)
        at org.koin.core.scope.Scope.get(Scope.kt:181)
        at com.debin.pokemonsearch.di.DataSourceModuleKt$dataSourceModule.invoke(DataSourceModule.kt:19)
        at com.debin.pokemonsearch.di.DataSourceModuleKt$dataSourceModule.invoke(Unknown Source:4)
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
            ... 72 more

添加到收藏夹用例:

class AddToFavourites(private val coreRepository: IPokemonCoreRepository) {
    suspend fun invokeAddToFavourites(pokemon: Pokemon) {
        coreRepository.addPokemonToFavourites(pokemon)
    }
}

领域层的存储库接口和模型

interface IPokemonCoreRepository {
    suspend fun addPokemonToFavourites(pokemon: Pokemon)
    suspend fun getFavouritePokemon() : List<Pokemon>
    suspend fun removePokemonFromFavourite(pokemon: Pokemon)
}

data class Pokemon(
    val id : Int,
    val name : String,
    val description : String,
    val imageUrl : String
)

数据层中的存储库实现和数据源:

class PokemonCoreRepository(private val dataSource: PokemonCoreDataSource) : IPokemonCoreRepository {
        override suspend fun addPokemonToFavourites(pokemon: Pokemon) {
            return dataSource.addPokemonToFavourites(pokemon)
        }
        
        override suspend fun getFavouritePokemon(): List<Pokemon> {
            return dataSource.getFavouritePokemon()
        }
        
        override suspend fun removePokemonFromFavourite(pokemon: Pokemon) {
            return dataSource.removePokemonFromFavourite(pokemon)
        }
    }

    interface PokemonCoreDataSource {
        suspend fun addPokemonToFavourites(pokemon: Pokemon)
        suspend fun getFavouritePokemon() : List<Pokemon>
        suspend fun removePokemonFromFavourite(pokemon: Pokemon)
    }

框架层的数据源实现:

class PokemonCoreDataSourceImpl(private val database : PokemonDatabase) : PokemonCoreDataSource{
    
    override suspend fun addPokemonToFavourites(pokemon: Pokemon) {
        return database.pfDao.addToFavourite(PokemonFavouriteEntity(id = pokemon.id, name = pokemon.name,
        description = pokemon.description, imageUrl = pokemon.imageUrl))
    }
    
    override suspend fun getFavouritePokemon(): List<Pokemon> {
        return database.pfDao.getFavouritePokemon().map {
          Pokemon(id = it.id, name = it.name, description = it.description, imageUrl = it.imageUrl)
        }
    }
    
    override suspend fun removePokemonFromFavourite(pokemon: Pokemon) {
          return database.pfDao.removeFromFavourite(PokemonFavouriteEntity(
              id = pokemon.id, name = pokemon.name,
              description = pokemon.description, imageUrl = pokemon.imageUrl
          ))
    }
}

参与模块:

val useCaseModule = module {
    factory { AddToFavourites(get()) }
    factory { GetFavourites(get()) }
    factory { RemoveFromFavourite(get()) }
}
   
val repositoryModule = module {
    single<IPokemonCoreRepository> { PokemonCoreRepository(get()) }
}
    
val dataSourceModule = module {
    single<PokemonCoreDataSource> { PokemonCoreDataSourceImpl(get()) }
}
    
val databaseModule = module {
    single { PokemonDatabaseFactory.getDBInstance(get()) }
}
    
val viewModelModule = module {
    viewModel { SearchViewModel(get(), get(), get()) }
}

框架层的数据库和实体:

@Database(entities = [PokemonFavouriteEntity::class], version = 1, exportSchema = false)
abstract class PokemonDatabase : RoomDatabase() {
    abstract val pfDao : PokemonFavouriteDao
}
    
object PokemonDatabaseFactory {
    fun getDBInstance(context: Context) {
        Room.databaseBuilder(context, PokemonDatabase::class.java, "PokemonDB")
            .fallbackToDestructiveMigration()
            .build()
    }
}
    
@Dao
interface PokemonFavouriteDao {
    @Insert(onConflict = REPLACE)
    suspend fun addToFavourite(pokemon : PokemonFavouriteEntity)
}
    
@Entity(tableName = "favourites")
data class PokemonFavouriteEntity(
    @PrimaryKey(autoGenerate = true) val id : Int,
    @ColumnInfo(name = "pokemonName") val name : String = "",
    @ColumnInfo(name = "pokemonDescription") val description : String = "",
    @ColumnInfo(name =  "pokemonImage")val imageUrl : String = ""
)

表示层中的Viewmodel:

class SearchViewModel (private val getPokemonDescription: GetPokemonDescription,
                       private val getPokemonSprites: GetPokemonSprites,
                       private val addToFavourites: AddToFavourites) : ViewModel() {

    private val _pokemon = MutableLiveData<Resource<PokemonResponse>>()
    private val _pokemonSprites = MutableLiveData<Resource<List<String>>>()
    private val _pokemonSpecies = MutableLiveData<Resource<PokemonSpeciesResponse>>()
    val pokemon: LiveData<Resource<PokemonResponse>> get() = _pokemon
    val pokemonSpecies: LiveData<Resource<PokemonSpeciesResponse>> get() = _pokemonSpecies


    fun getPokemonDetails(pokemonName: String) {
        _pokemon.value = Resource.Loading()
        getPokemonSprites.execute(PokemonSubscriber(), pokemonName)
    }

    fun getPokemonSpeciesDetails(pokemonName: String) {
        _pokemonSpecies.value = Resource.Loading()
        getPokemonDescription.execute(PokemonSpeciesSubscriber(), pokemonName)
    }

    fun addToFavourite() {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                addToFavourites.invokeAddToFavourites(getPokemonDetails())
            }
        }
    }

    inner class PokemonSubscriber : DisposableSingleObserver<PokemonResponse>() {
        override fun onSuccess(pokemonResponse: PokemonResponse) {
            _pokemon.value = Resource.Success(pokemonResponse)
        }

        override fun onError(error: Throwable) {
            _pokemon.value = Resource.Error(error.message)
        }
    }

    inner class PokemonSpeciesSubscriber : DisposableSingleObserver<PokemonSpeciesResponse>() {
        override fun onSuccess(pokemonSpeciesResponse: PokemonSpeciesResponse) {
            _pokemonSpecies.value = Resource.Success(pokemonSpeciesResponse)
        }

        override fun onError(error: Throwable) {
            _pokemonSpecies.value = Resource.Error(error.message)
        }
    }

    private fun getPokemonDetails(): Pokemon {
        var pokemonId = 0
        var pokemonName = ""
        var pokemonDescription = ""
        var pokemonImage = ""
        _pokemon.observeForever {
            when (it) {
                is Resource.Success -> {
                    pokemonImage = it.result.sprites.front_default
                }
                else -> {

                }
            }
        }
        _pokemonSpecies.observeForever {
            when (it) {
                is Resource.Success -> {
                    pokemonId = it.result.id
                    pokemonName = it.result.name
                    pokemonDescription = it.result.flavor_text_entries[0].flavor_text
                }
                else -> {

                }
            }
        }

        return Pokemon(pokemonId, pokemonName, pokemonDescription, pokemonImage)
    }

    override fun onCleared() {
        super.onCleared()
        getPokemonDescription.dispose()
        getPokemonSprites.dispose()
    }
}

您没有returning 创建的数据库实例。添加 return 语句到工厂函数或 return 使用 =

像这样:

object PokemonDatabaseFactory {
    fun getDBInstance(context: Context) =
        Room.databaseBuilder(context, PokemonDatabase::class.java, "PokemonDB")
            .fallbackToDestructiveMigration()
            .build()
    
}

更新

实际上,您不需要数据库中的工厂函数。您可以通过 Koin 直接从模块创建一个 DB 对象,如下所示:

single {
            Room.databaseBuilder(context, PokemonDatabase::class.java, "PokemonDB")
                 .fallbackToDestructiveMigration()
                 .build()
        }