基于KSP实现简化版本的Arouter Autowired实现, 功能完全相同
1、 首先配置kotlin和ksp版本, 要求kotlin大于等于1.6.10; 注意:ksp版本需要和实际kotlin版本相匹配;点击此处 查询KSP版本
Wired项目中kotlin和ksp版本号分别为1.6.10和1.6.10-1.0.4, 故以kotlin 1.6.10为例 在根目录build.gradle下配置ksp的版本号
buildscript {
ext.kotlin_version = '1.6.10'
}
plugins {
id 'com.google.devtools.ksp' version '1.6.10-1.0.4' apply false
}
在需要接入Wired的模块build.gradle中导入ksp插件
plugins {
id 'com.google.devtools.ksp'
}
// or--> apply plugin: 'com.google.devtools.ksp'
如果需要模块内的生成的KSP代码可以被IDE识别, 请在模块的build.gradle中任意一行进行如下的配置:
android.sourceSets.all { it.java.srcDir("build/generated/ksp/${it.name}/kotlin/") }
注:ksp生成的代码默认会被编译到app中,但是默认对IDE不可见
1、 首先导入jitpack仓库
maven { url 'https://jitpack.io' }
2、 配置kotlin、ksp, 然后导入api模块和注解处理器模块
implementation 'com.github.JailedBird.Wired:lib_api:0.9.9'
ksp 'com.github.JailedBird.Wired:lib_compiler:0.9.9'
类似Arouter的结构,Wired分为三个模块
- lib_api(Wired api)
- lib_compiler(Wired compiler)
- lib_annotation(Wired annotation)
lib_api通过api的形式依赖lib_annotaion, 因此不需要单独导入lib_annotation
建议在 gradle.properties 开启如下三个配置
# KSP Incremental processing
# https://kotlinlang.org/docs/ksp-incremental.html#program-elements
ksp.incremental=true
ksp.incremental.log=true
# track classpath
ksp.incremental.intermodule=true
1、 是增量编译, 默认开启 2、增量编译的相关日志(生成路径:模块下build下kspcache) 3、 我不是很熟,但是建议开启
支持8种基础数据类型(非空)、withString
(可空)、withParcelable
(可空)、withSerializable
(可空)、withObject
(可空)
(PS:待优化->提供快速启动Activity的ktx)
private fun gotoSecond() {
val bundle = WiredBuilder.Builder()
.withString("name", "abelzhao")
.withInt("age", 23)
.withObject("testObj", TestObj("p1", "p2"))
.withObject("nameList", listOf("1", "2", "3"))
.withParcelable("testParcelable", TestParcelable("p1", "p2"))
.withObject(
"testParcelableList",
listOf(
TestParcelable("p1", "p2"),
TestParcelable("p1", "p2"),
TestParcelable("p1", "p2")
)
)
.withSerializable("testSerializable", TestSerializable("p1", "p2"))
.withObject(
"testSerializableList",
listOf(
TestSerializable("p1", "p2"),
TestSerializable("p1", "p2"),
TestSerializable("p1", "p2")
)
)
.withObject("testEnum", TestEnum.A)
.build()
val intent = Intent(this, SecondActivity::class.java)
intent.putExtras(bundle)
startActivity(intent)
}
注意:
1、 List<Parcelable>
这种的统一按照Obj对象处理, 内部通过GSON实现, 这也是为啥最好使用WiredBuilder构建我们的参数(当然除Obj类型外也可以不使用WiredBuilder)
2、 支持枚举,同样按照Object类型传递参数 (PS: 建议使用枚举而非数字判定Activity的打开类型)
SecondActivity.kt
@Wired(required = true)
var char: Char = 'c'
@Wired
var charNullable: Char? = null
@Wired
var int: Int = 1
@Wired
var intNullable: Int? = null
@Wired
var name: String = ""
@Wired(required = true)
var nameNullable: String? = ""
@Wired
var testEnum: TestEnum = TestEnum.OTHER
@Wired
var nameList: List<String> = emptyList()
@Wired
var age: Int = 0
@Wired
var testObj: Any? = null
@Wired
var testParcelable: TestParcelable? = null
@Wired
var testParcelableList: List<TestParcelable>? = null
@Wired
var testSerializable: TestSerializable? = null
@Wired
var testSerializableList: List<TestSerializable>? = null
注意:
1、 鉴于Wired没得历史包袱,设计其仅支持kotlin; 也是为了减少潜在的问题,Java中使用Wired会直接编译错误
2、 参数类型不允许为val
, 因为val属于不可变, 无法为其注入
(SecondActivity) 生成的范式如下:
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY Wired
*/
public class `SecondActivity$$Wired$$Autowired` : ISyringe {
public override fun inject(target: Any?): Unit {
val substitute = (target as? SecondActivity)?: throw IllegalStateException(
"""The target that needs to be injected must be SecondActivity, please check your code!"""
)
substitute.intent?.extras?.let {
substitute.char = it.getChar("char", substitute.char)
}
substitute.intent?.extras?.let {
if(it.containsKey("charNullable")) {
substitute.charNullable = it.getChar("charNullable")
}
}
substitute.intent?.extras?.let {
substitute.int = it.getInt("int", substitute.int)
}
substitute.intent?.extras?.let {
if(it.containsKey("intNullable")) {
substitute.intNullable = it.getInt("intNullable")
}
}
substitute.intent?.extras?.let {
substitute.name = it.getString("name", substitute.name)
}
substitute.intent?.extras?.let {
substitute.nameNullable = it.getString("nameNullable", substitute.nameNullable)
}
if (substitute.nameNullable == null) {
Log.e("Wired::" , """The field 'nameNullable' in class 'SecondActivity' is null!""")
}
substitute.intent?.extras?.let {
substitute.testEnum = SerializationServiceImpl.parseObject(it.getString("testEnum"), (object :
TypeWrapper<TestEnum>(){}).type)
}
substitute.intent?.extras?.let {
substitute.nameList = SerializationServiceImpl.parseObject(it.getString("nameList"), (object :
TypeWrapper<List<String>>(){}).type)
}
substitute.intent?.extras?.let {
substitute.age = it.getInt("age", substitute.age)
}
substitute.intent?.extras?.let {
substitute.testObj = SerializationServiceImpl.parseObject(it.getString("testObj"), (object :
TypeWrapper<Any?>(){}).type)
}
substitute.intent?.getParcelableExtra<TestParcelable?>("testParcelable")?.let {
substitute.testParcelable = it
}
substitute.intent?.extras?.let {
substitute.testParcelableList =
SerializationServiceImpl.parseObject(it.getString("testParcelableList"), (object :
TypeWrapper<List<TestParcelable>?>(){}).type)
}
(substitute.intent?.getSerializableExtra("testSerializable") as? TestSerializable?)?.let {
substitute.testSerializable = it
}
substitute.intent?.extras?.let {
substitute.testSerializableList =
SerializationServiceImpl.parseObject(it.getString("testSerializableList"), (object :
TypeWrapper<List<TestSerializable>?>(){}).type)
}
}
}
在合适的时机获取参数
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
WiredInjector.inject(this)
}
1、 支持任何类型, 且不需要混淆(模块内部已经处理), 但是也不要想着传递图片、超大的对象这种*操作
2、 有任何bug可以向我即是反馈
3、 目前ksp默认是通过warn打印操作日志的,看起来可能会报红, 不要在意, 希望取消可以提issue
4、 增量编译下, 当且仅当 当前文件或Wired关联的类文件变化,才会导致注解处理器为这个文件重新生成注入文件, 因此几乎不存在编译耗时问题
● https://kotlinlang.org/docs/ksp-overview.html#symbolprocessorprovider-the-entry-point