Koin (可以理解为注入框架),在Android 使用频繁,并且Koin官方专门给Android做了依赖库。
使用起来非常方便。
我们可以通过看官网的例子快速入门。
这里根据官方给出的例子,加上自己的理解和使用过程中遇到的问题, 做了个简单记录。
1. 官网首页
https://insert-koin.io/
2. change log:
https://github.com/InsertKoinIO/koin/blob/main/CHANGELOG.md
3. 快速入门 (Kotlin/Android)
Android | Koin
https://insert-koin.io/docs/quickstart/kotlin
(1) 根目录build.gradle 设置Koin版本
buildscript {
ext {
koin_version = "3.2.0"
}
(2) app/build.gradle 添加koin-android 依赖
dependencies {
// Koin for Android
implementation "io.insert-koin:koin-android:$koin_version" //包含了核心库 org.koin.core
}
(3) 创建接口 HelloRepository / 实现类 HelloRepositoryImpl / 包装类类MySimplePresenter
(4) 声明 koin module , 用于创建单例
val appModule = module {
// single instance of HelloRepository
single<HelloRepository> { HelloRepositoryImpl() }
// Simple Presenter Factory
factory { MySimplePresenter(get()) }
}
(5) 启动Koin (在App创建的时候,加载module, 即去创建单例)
class MyApplication : Application(){
override fun onCreate() {
super.onCreate()
// Start Koin
startKoin{ // @ org.koin.core.context
androidLogger()
androidContext(this@MyApplication) //android扩展库 org.koin.android.ext.koin
modules(appModule) // org.koin.core.KoinApplication
}
}
}
(6) 真正使用 (注入依赖)
val firstPresenter: MySimplePresenter by inject()
>>> 这里的inject是 org.koin.android.ext.android.inject
(为啥不用 org.koin.java.KoinJavaComponent.inject ???? 专门给android做了封装???)
4. 在Android中的优势
(1) 非Activity/Service 等想要获取Context 时,可以通过 androidContext(applicationContext) 注入依赖
其它地方则可以通过注入获取,不需要单独创建API 传递Context实例,大大减少代码量和复杂度
java: Context context = get(Context.class) 或 Lazy<Context> mContext = inject(Context.class)
Kotlin : val appContext = get<Context>() 或者 val context:Context by inject()
androidContext实现源码(与自己实现类似: single {XXXX})
fun KoinApplication.androidContext(androidContext: Context): KoinApplication {
if (koin.logger.isAt(Level.INFO)) {
koin.logger.info("[init] declare Android Context")
}
if (androidContext is Application) {
koin.loadModules(listOf(module {
single { androidContext } binds arrayOf(Context::class,Application::class)
}))
} else {
koin.loadModules(listOf(module {
single{ androidContext }
}))
}
return this
}
附-问题汇总
1. kotlin libraries attached to this project were compiled with a newer kotlin compiler and can't be read ,
please update kotlin plugin
kotlin库附加到这个项目是用更新的kotlin编译器编译的,不能读取,请更新kotlin插件
2. 在Java 中通过 inject 延迟注入、 get立刻注入
https://stackoverflow.com/questions/50668797/inject-koin-in-java-classes
用法: inject(类名.class) / get(类名.class)
// 延迟注入,sizePref.loadHeight error (赋值给变量,显示调用它的函数会报错)
Lazy<SizePreference> sizePref = inject(SizePreference.class); //延迟注入
SizePreference sizePref = get(SizePreference.class); // 立刻注入
注:需要导入静态方法:import static org.koin.java.KoinJavaComponent.get;
3. Kotlin 使用inject : SizeProvider: ISizeProvider by inject()
提示:No value passed for parameter 'clazz'
原因: 在非 Activity 或者 Fragment中使用,需要实现 KoinComponent
解决方法:
所在类 实现KoinComponent ,需要导入这两个包
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
参考:
https://stackoverflow.com/questions/61260337/trying-to-use-koin-but-doesnt-work-correctly-on-android
延申: java 使用get(类名.class) kotlin 使用 by inject() ???
>>>两种语言都可以使用get 或延迟加载 inject
4. 使用inject时,定义为Lazy, 因为它是延迟加载的
private final Lazy<Context> mContext = inject(Context.class);
使用mContext时,需要 mContext.getValue()
5. java 使用 get(XXX.class) 时,需要强转
例如: ((Context) get(Context.class)).getResources()..
或者:
Context context = get(Context.class);
context.getResources()...