koin_用Koin进行依赖注入

koin

Koin can bring easy dependency injection to android, standalone or web application projects. This tutorial will show how to use Koin on your Android project.

Koin可以为Android,独立或Web应用程序项目带来轻松的依赖项注入。 本教程将展示如何在您的Android项目中使用Koin

If you just want to download the code and check it by yourself, the repository is : https://github.com/lluzalves/KoinApp

如果您只想下载代码并自己检查,则存储库为: https : //github.com/lluzalves/KoinApp

But what is dependency injection anyways?

但是,依赖注入到底是什么?

An application can be composed of many objects that will eventually have to collaborate to perform tasks. When this happens, we call it a dependency.

一个应用程序可以由许多对象组成,这些对象最终将不得不协作来执行任务。 发生这种情况时,我们称其为依赖项。

Because of its dependencies, a class will have to obtain references to the required dependents objects and that will make it committed to a particular set of objects. Most of the time these required dependencies are passed through the constructor.

由于其依赖关系,一个类将必须获取对所需依赖对象的引用,这将使其提交给一组特定的对象。 大多数情况下,这些必需的依赖项通过构造函数传递。

When an application becomes more complex and grows in size it might have issues related to code reusability and an increasing need to apply refactor. To handle this kind of issue, we can make use of the dependency injection technique, by diverging usage and creation of dependencies.

当应用程序变得更加复杂且规模不断增长时,它可能会遇到与代码可重用性相关的问题,以及对应用重构的需求不断增加。 为了处理这种问题,我们可以使用依赖注入技术, 通过 发散依赖性的使用和创造。

Let’s add Koin to our project!

让我们将Koin添加到我们的项目中!

To add Koin to the project, open the build.gradle file and add the following Koin dependency and sync :

要将Koin添加到项目中,请打开build.gradle文件并添加以下Koin dependency并进行同步:

implementation "org.koin:koin-android:2.0.1"
testImplementation "org.koin:koin-test:2.0.1"
testImplementation "com.nhaarman:mockito-kotlin:1.5.0"
Image for post

If the application is modularized, change implementation to api so you can access Koin it in other modules, if required.

如果应用程序模块化,变更implementationapi ,所以你可以访问Koin它在其他模块中,如果需要的话。

Let’s write our first Koin module!

让我们编写第一个Koin模块!

Now, create a Kotlin file named ApplicationModules , it will contain the dependencies we want to inject.

现在,创建一个名为ApplicationModules的Kotlin文件,它将包含我们要注入的依赖项。

Image for post

A Koinmodule is a space to declare components. It allows you to provide a collection of objects that will persist with the entire context lifetime that it belongs to.

Koin模块是用于声明组件的空间。 它允许您提供一个对象集合,这些对象将在其所属的整个上下文生命周期内保持不变。

To define a module use the module block and declare the dependencies inside of it:

要定义模块,请使用module块并在其中声明依赖项:

Image for post
ApplicationModule.kt
ApplicationModule.kt

Now let’s initialize Koin!

现在让我们初始化Koin!

In case the project don’t have a custom Application class, you will need to create one and declare it in your manifest file.

如果项目没有自定义Application class ,则需要创建一个并在清单文件中声明它。

Image for post

Your custom App class should override OnCreate() method and call startKoin(), it is responsible to return a KoinApplication instance that represents a Koin Container configuration with all the modules and definitions that was declared in startKoin(). Attention, startKoin() should only be called once.

您的自定义App类应重写OnCreate()方法并调用startKoin() ,它负责返回一个KoinApplication实例,该实例代表具有在startKoin()声明的所有模块和定义的Koin Container配置。 注意, startKoin()仅应调用一次。

androidLogger() is used to set the Koin log level.

androidLogger()用于设置Koin日志级别。

androidContext() can be used to set the application Context to the Koin Container but also to inject it when necessary.

androidContext()可以用于将application Context设置为Koin Container ,也可以在必要时进行注入。

modules() is used to set the modules that we have declared to be attached to the container.

modules()用于设置我们声明要附加到容器的模块。

To finish this process open the Manifest , and set the value of the property android:name to your custom App class.

要完成此过程,请打开Manifest ,然后将android:name属性的值设置为自定义App类。

Image for post

Injection time!

注射时间!

For Koin we can have 3 types of scope. We can define it as:

对于Koin我们可以使用3种类型的scope 。 我们可以将其定义为:

single, which is a singleton, this type of scope will persist for the entire application lifetime.

single ,这是一个singleton ,这种类型的scope将在整个应用程序生存期内持续存在。

factory, for this type, Koin will provide a new object for each time we require an instance.

factory ,对于这种类型,每次需要实例时, Koin都会提供一个新对象。

scoped, in this case, Koinwill provides an object that will persist as long the associated scope lifetime exists.

scoped ,在这种情况下, Koin将提供一个对象,只要关联的scope生存期存在,该对象将持续存在。

In this tutorial, we will only talk about single and factory .

在本教程中,我们仅讨论singlefactory

Use case as single.

用例为 single

The most common ways to resolve dependencies with Koin is by: implementing the KoinComponent interface or providing the required dependency through constructor injection.

解决Koin依赖关系的最常见方法是:实现KoinComponent接口或通过constructor injection提供所需的依赖关系。

Implementing the KoinComponent interface is faster, it gives the class access to Koin features like get() and inject() but we can solve this with a better approach by using constructor injection .

实现KoinComponent接口的速度更快,它使类可以访问Koin功能,如get()inject()但是我们可以使用constructor injection使用更好的方法来解决此问题。

The constructor injection approach makes the process simpler, because the class will only care about the dependencies it needs and not about who will satisfy them.

constructor injection方法使过程更简单, 因为该类仅关心其所需的依赖关系,而不关心谁将满足它们。

It offers a more robust way to have consistent state, as soon as the class is constructed and not only when the field injection is completed and it makes testing easier because we are declaring the dependencies in the constructor.

一旦构造了类,它不仅提供了字段注入完成后的状态,而且提供了一种更可靠的状态一致状态,这使测试更加容易,因为我们在构造函数中声明了依赖项。

Approach 1 - Constructor injection.

方法1-构造函数注入。

Let’s say your application needs to store and provide data using SharedPreferences, this class should be able to provide a way to put and retrieve data from a SharedPreferences and it will also have a Context dependency.

假设您的应用程序需要使用SharedPreferences来存储和提供数据,该类应该能够提供一种方法来从SharedPreferences放置和检索数据,并且它还具有Context依赖性。

Image for post

When we started Koin , the Context was injected and now can be retrieved by calling androidContext() .

当我们启动KoinContext被注入,现在可以通过调用androidContext()进行检索。

Image for post

We are going to declare a single, and pass the Contextto the object constructor, that way Koin can provide the AppPreferences dependency that we want to use.

我们将声明一个single ,并将Context传递给对象构造函数,这样Koin可以提供我们要使用的AppPreferences依赖项。

In our Activity, Fragment or Service classes, it is easy to retrieve declared instances from Koin modules. Theses classes have access to Koin features like:

在我们的ActivityFragmentService类中,很容易从Koin模块中检索声明的实例。 这些类可以访问Koin功能,例如:

by inject() — lazy injected

by inject() —延迟注入

get() — eager injected

get() —渴望注入

release() — release module’s instance

release() —释放模块的实例

getProperty() / setProperty() — get/set property

getProperty() / setProperty() —获取/设置属性

In this case, we will make use of by inject() , to lazy inject the AppPreferences.

在这种情况下,我们将使用by inject()来延迟注入AppPreferences

Image for post

Now it is possible to inject the AppPreferences instance and use it to put or retrieve data from SharedPreferences.

现在可以注入AppPreferences实例,并使用它来放置或从SharedPreferences检索数据。

Approach 2 - Implementing the KoinComponent.

方法2-实现 KoinComponent

If AppPreferences implements the KoinComponent , it gives the class access to the same Koin features that we have in the MainActivity, so it is possible to use by inject() to inject the Context lazily in AppPreferences.

如果AppPreferences实现了KoinComponent ,它将为类提供与MainActivity相同的Koin功能的访问权限,因此可以by inject()来将Context延迟地注入AppPreferences

Image for post
Image for post

Use case as factory.

用例作为 factory

While single provides a unique instance during the entire application lifecycle, factory will provide a new instance of the requested dependency every time it needs to be injected.

尽管single在整个应用程序生命周期中提供了唯一的实例,但是factory每次需要注入时都会提供所请求依赖的新实例。

Let’s improve our previous example by applying the MVP design pattern to make use of factory .

让我们通过应用MVP设计模式来使用factory来改进前面的示例。

Image for post
Image for post

Now that things are more clear, the Presenter will be responsible to return the profile name and should notify the View when everything is completed, the MainActivity that implements the View will be responsible to show the data and it will have the presenter lazily injected by Koin.

现在,一切变得更清楚了, Presenter将负责返回配置文件名称,并在完成所有操作后通知View ,实现ViewMainActivity将负责显示数据,并且演示者将由Koin延迟注入。

To declare the presenter dependency, we will use factory. As long as a MainContract.MainView is given, the factory will return a new MainPresenter instance. Add the following code to applicationModule file :

要声明presenter依赖项,我们将使用factory. 只要给出MainContract.MainViewfactory将返回一个新的MainPresenter实例。 将以下代码添加到applicationModule文件:

Image for post

MainView needs to be provided so Koincan be able to inject the presenter in the MainActivity, to do this use paramentersOf() expression available in Koin , it allows to indicate input arguments for the object constructor and it will pass the required view to the presenter factory.

需要提供MainView以便Koin能够在MainActivity注入演示者,为此可以使用Koin可用的Koin paramentersOf()表达式,它可以指示对象构造函数的输入参数,并将所需的视图传递给演示者factory

Image for post

Let’s Test.

让我们测试一下。

Let’s see if the presenter is behaving as expected. The test class should implement KoinTest interface, so we can do our injections properly. Koin needs to be started before we run the tests.

让我们看看演示者的行为是否符合预期。 测试类应该实现KoinTest接口,因此我们可以正确地进行注入。 在运行测试之前,需要启动Koin。

Image for post

By using Mockito.verify() we are checking if after calling presenter.onComplete() any interaction happened to our view mock, specifically the showData() method.

通过使用Mockito.verify()我们检查调用presenter.onComplete()之后是否对我们的视图模拟发生了任何交互,特别是showData()方法。

Now just run the test and see the result. That’s it for now. Thanks for reading. :)

现在只需运行测试并查看结果。 现在就这样。 谢谢阅读。 :)

翻译自: https://medium.com/swlh/dependency-injection-with-koin-for-android-43dda4d800d1

koin

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin 依赖注入是一种设计模式,它可以帮助我们解耦代码并提高可测试性。Kotlin 中常用的依赖注入框架有 Koin 和 Dagger2。 Koin一个轻量级的依赖注入框架,它使用 Kotlin 语言特性来实现依赖注入Koin 简单易用,不需要编写任何代码,只需要定义模块和依赖关系即可。以下是一个使用 Koin 进行依赖注入的示例: ```kotlin // 定义一个模块 val appModule = module { single { NetworkService() } factory { UserRepository(get()) } viewModel { MainViewModel(get()) } } // 在 Application 中初始化 Koin class MyApp : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MyApp) modules(appModule) } } } // 在 Activity 中使用依赖注入 class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by viewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 使用 viewModel viewModel.doSomething() } } ``` Dagger2 是一个功能强大的依赖注入框架,它可以在编译时生成依赖注入代码,提高运行时的性能。Dagger2 的使用比 Koin 更为复杂,需要定义组件、模块、依赖关系等。以下是一个使用 Dagger2 进行依赖注入的示例: ```kotlin // 定义一个模块 @Module class AppModule { @Provides fun provideNetworkService(): NetworkService { return NetworkService() } @Provides fun provideUserRepository(networkService: NetworkService): UserRepository { return UserRepository(networkService) } } // 定义一个组件 @Component(modules = [AppModule::class]) interface AppComponent { fun inject(activity: MainActivity) } // 在 Application 中初始化 Dagger2 class MyApp : Application() { lateinit var appComponent: AppComponent override fun onCreate() { super.onCreate() appComponent = DaggerAppComponent.builder() .build() } } // 在 Activity 中使用依赖注入 class MainActivity : AppCompatActivity() { @Inject lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 注入依赖 (application as MyApp).appComponent.inject(this) // 使用 viewModel viewModel.doSomething() } } ``` 总体来说,Koin 适合小型项目和快速原型开发,而 Dagger2 则适合大型项目和需要高性能的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值