我们如何使用 Koin 为 ViewModel 注入依赖项?
所以例如,我有一个ViewModel
这样的:
class SomeViewModel(val someDependency: SomeDependency, val anotherDependency: AnotherDependency): ViewModel()
Run Code Online (Sandbox Code Playgroud)
现在这里的官方文档指出,要提供一个ViewModel
我们可以执行以下操作:
val myModule : Module = applicationContext {
// ViewModel instance of MyViewModel
// get() will resolve Repository instance
viewModel { SomeViewModel(get(), get()) }
// Single instance of SomeDependency
single<SomeDependency> { SomeDependency() }
// Single instance of AnotherDependency
single<AnotherDependency> { AnotherDependency() }
}
Run Code Online (Sandbox Code Playgroud)
然后注入它,我们可以这样做:
class MyActivity : AppCompatActivity(){
// Lazy inject SomeViewModel
val model : SomeViewModel by viewModel()
override fun …
Run Code Online (Sandbox Code Playgroud) 我正在使用 koin 学习 kotlin。在目录中运行应用程序时,我看到以下消息。
java.lang.IllegalStateException:KoinApplication 尚未启动
虽然我在 MyApplication 中使用了startKoin
class MyApplication : Application() {
var listOfModules = module {
single { GitHubServiceApi() }
}
override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this@MyApplication)
modules(listOfModules)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我发现了我犯了错误的问题。我应该在 mainfest.xml 中添加 MyApplcation 名称
我正在尝试在执行数据库插入的应用程序存储库类中测试这个函数。我正在Koin
用作我的依赖注入库。为了进行测试,我需要创建一个内置于内存的数据库版本。要创建该数据库,我需要 Android 应用程序上下文。所以我创建了我的测试类,如下所示。
import android.content.Context
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
import com.chathuranga.shan.mycontacts.di.applicationModule
import com.chathuranga.shan.mycontacts.di.repositoryModule
import com.chathuranga.shan.mycontacts.room.AppDatabase
import org.junit.After
import org.junit.Test
import org.junit.Before
import org.junit.Rule
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.loadKoinModules
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.dsl.module
import org.koin.test.KoinTest
import org.koin.test.inject
import org.mockito.MockitoAnnotations
class ContactRepositoryTest : KoinTest {
private val contactRepository: ContactRepository by inject()
private lateinit var appDatabase: AppDatabase
@get:Rule
val rule = InstantTaskExecutorRule()
@Before
fun setUp() {
startKoin {
printLogger()
modules(listOf(applicationModule,repositoryModule))
}
MockitoAnnotations.initMocks(this)
val context = ApplicationProvider.getApplicationContext<Context>() …
Run Code Online (Sandbox Code Playgroud) 我正在使用 Kotlin 开发一个 Android 应用程序,我需要在其中获取移动设备的当前位置。我已经在各种示例中找到了一种方法,但我不知道如何根据 Clean Architecture 与 MVVM 集成此逻辑。
在我的架构中,我有以下几层:表示层、用例层、数据层、域层和框架层。我用 MVVM 模式组织了表示层。我还使用 Koin 进行依赖注入。
我从框架层中的数据源获取应用程序所需的所有数据。例如,远程获取的数据或从数据库获取的数据,或设备(位置)提供的数据。
以下是从 ViewModel 获取位置所涉及的文件示例:
ConfigurationViewModel(表示层):
class ConfigurationViewModel(private val useCase: GetLocationUseCase) : ViewModel() {
fun onSearchLocationButtonClicked() = liveData<Resource<Location>>(Dispatchers.IO) {
emit(Resource.loading())
try {
emit(Resource.success(data = useCase.invoke(UseCase.None())))
} catch (exception: Exception) {
emit(Resource.error(message = exception.message))
}
}
Run Code Online (Sandbox Code Playgroud)
GetLocationUseCase(用例层):
class GetLocationUseCase(private val locationRepository: LocationRepository) :
UseCase<Location, UseCase.None>() {
override suspend fun invoke(params: None): Location = locationRepository.getLocation()
}
Run Code Online (Sandbox Code Playgroud)
LocationRepositoryImpl(数据层):
class LocationRepositoryImpl(private val locationDeviceDataSource: LocationDeviceDataSource) :
LocationRepository {
override suspend fun …
Run Code Online (Sandbox Code Playgroud) 我的视图模型模块如下所示:
val viewModelModule = module {
viewModel { (id: Int, user: String, email: String) ->
MyViewModel(get(), get(), id = id, user = user, email = email)
}
}
Run Code Online (Sandbox Code Playgroud)
因此视图模型总共接受五个参数,前两个是存储库,下面是它们的模块:
val firstRepositoryModule = module {
single {
FirstRepository()
}
}
Run Code Online (Sandbox Code Playgroud)
val secondRepositoryModule = module {
single {
SecondRepository()
}
}
Run Code Online (Sandbox Code Playgroud)
我知道这个示例代码,但这里的视图模型不接受任何参数,所以它不能回答我的问题
我正在尝试使用Koin创建用户范围。记录用户时,我正在创建范围:
val scope = getKoin().createScope("USER_SCOPE")
Run Code Online (Sandbox Code Playgroud)
当用户单击注销时,我正在破坏范围
scope?.let {userScope ->
userScope.close()
getKoin().deleteScope(userScope.id)
}
Run Code Online (Sandbox Code Playgroud)
在我的koin模块中,我有一个scoped
UserRepository,它只能在用户会话期间使用。我也有使用此存储库的ViewModels和Use Cases,我尝试将存储库注入scoped
其中
val appModule = module {
scoped<UserRepository> { UserDataRepository() }
viewModel { UserViewModel(getScope("USER_SCOPE").get()) }
factory { MyUseCase(getScope("USER_SCOPE").get()) }
}
Run Code Online (Sandbox Code Playgroud)
第一次登录时,它可以正常工作,我在视图模型和用例中注入了用户存储库。但是在注销(删除作用域)之后和再次登录后,UserRepository实例仍然完全相同。
我会在示波器用法中错过某些东西吗?
我创建了一个抽象BaseFragment
类,它将被其他具体Fragment
类扩展。我想注入ViewModel
我BaseFragment
使用的Koin
. 这是我的 BaseFragment:
abstract class BaseFragment<out VM : BaseViewModel, DB : ViewDataBinding>(private val mViewModelClass: Class<VM>) : Fragment() {
val viewModel: VM by viewModel()
open lateinit var binding: DB
fun init(inflater: LayoutInflater, container: ViewGroup) {
binding = DataBindingUtil.inflate(inflater, getLayoutRes(), container, false)
}
open fun init() {}
@LayoutRes
abstract fun getLayoutRes(): Int
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
init(inflater, container!!)
init()
super.onCreateView(inflater, container, savedInstanceState)
return binding.root
}
open …
Run Code Online (Sandbox Code Playgroud) 假设我有两个接口,例如:
interface LetterClassifier
interface NumberClassifier
Run Code Online (Sandbox Code Playgroud)
然后这些接口将应用于这个类:
class Classifier() : LetterClassifier, NumberClassifier
Run Code Online (Sandbox Code Playgroud)
现在,我想提供这些实例只是作为LetterClassifier
和NumberClassifier
不作为Classifier
在Koin
。
我认为这样做的方法是:
module {
val classifier = Classifier()
single<NumberClassifier> { classifier }
single<LetterClassifier> { classifier }
}
Run Code Online (Sandbox Code Playgroud)
但我不认为这是正确的方法。有人可以指导我吗?
我有以下 ViewModel 设置:
interface FooViewModel {}
class FooViewModelImpl: ViewModel(), FooViewModel {}
Run Code Online (Sandbox Code Playgroud)
我想通过 Koin 提供它,如下所示:
viewModel<FooViewModel> { FooViewModelImpl() }
Run Code Online (Sandbox Code Playgroud)
它不起作用,因为 Koin 在定义中需要 ViewModel 而不是 FooViewModel,而且我不想让我的 FooViewModel 成为从 ViewModel 扩展的抽象类。
有什么办法可以通过 Koin 做到这一点吗?
我想知道如何使用 Koin 库正确确定依赖范围。
由于 Google 推荐了单一Activity
架构,因此AndroidX 导航库已成为通过轻松交换Fragment
s来促进这一点的关键库。
典型的现代 Android 应用程序在包和/或Gradle
模块中具有多个分离的功能。
这些功能模块提供了一个可以在根图中用作嵌套图的图。(见图)
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_graph"
app:startDestination="@id/mainFragment">
<include app:graph="@navigation/nav_graph_feature_a" />
<include app:graph="@navigation/nav_graph_feature_b" />
<fragment
android:id="@+id/mainFragment"
android:name="com.example.androidx_navigation.MainFragment"
android:label="MainFragment"
tools:layout="@layout/fragment_main">
<action
android:id="@+id/action_mainFragment_to_featureAFragment1"
app:destination="@id/nav_graph_feature_a" />
<action
android:id="@+id/action_mainFragment_to_featureBFragment1"
app:destination="@id/nav_graph_feature_b" />
</fragment>
</navigation>
Run Code Online (Sandbox Code Playgroud)
应遵守以下规则:
更具体地说:
如何在 Koin 中实现这一目标?
请注意,共享依赖项不仅限于 ViewModel。
我应该能够在我的范围内共享任何任意类。
android koin android-architecture-navigation navigation-architecture koin-scope
koin ×10
android ×8
kotlin ×8
viewmodel ×2
android-architecture-navigation ×1
interface ×1
koin-scope ×1
mvvm ×1
unit-testing ×1