在Kotlin中使用注释处理Android框架 kapt
时间:2017-05-29 00:28:59
收藏:0
阅读:12923
本教程介绍如何在 Kotlin 中使用依赖于注释处理的流行的 Android 框架和库。
在日常 Android 开发中,流行着数以千计的框架帮助我们提升开发效率。 使用 Kotlin 开发时仍然可以沿用这些框架,而且和使用 Java 同样简单。 本章教程将提供相关示例并重点介绍配置的差异。
教程以 Dagger、 Butterknife、 Data Binding、 Auto-parcel 以及 DBFlow 为例(其它框架配置基本类似)。 以上框架均基于注解处理方式工作:通过对代码注解自动生成模板代码。 注解有助于减少冗余代码,让代码清晰可读,想要了解运行时的代码,可以直接阅读自动生成的源代码。 但所有生成的代码均为 Java 代码而非 Kotlin。
在 Kotlin 中添加依赖与 Java 中类似,仅需要使用 Kotlin 注解处理工具(Kotlin Annotation processing tool,kapt)替代 annotationProcessor 即可。
Dagger
Dagger 是著名的依赖注入框架。 如果对它还不了解,可以查阅用户手册。 我们已经将整个咖啡示例 使用 Kotlin 重写,详细代码在这里。 Kotlin 代码与 Java 非常相似,所有示例代码可在同一个文件内查看。
与 Java 一样,Dagger 通过 @Inject 对构造函数注解,进而创建类的实例。 而 Kotlin 使用更简洁的语法同时声明属性和构造函数参数。 在 Kotlin 中对构造函数进行注解,必须显式使用 constructor 关键字,并在关键字前声明 @Inject。
class Thermosiphon
@Inject constructor(
private val heater: Heater
) : Pump {
// ……
}
@Module
abstract class PumpModule {
@Binds
abstract fun providePump(pump: Thermosiphon): Pump
}
@Module(includes = arrayOf(PumpModule::class))
class DripCoffeeModule {
@Provides @Singleton
fun provideHeater(): Heater = ElectricHeater()
}
使用 @Component 为类型生成依赖注入的实现。 自动生成类文件的类名带有 Dagger 前缀,比如下文示例 DaggerCoffeeShop:
@Singleton
@Component(modules = arrayOf(DripCoffeeModule::class))
interface CoffeeShop {
fun maker(): CoffeeMaker
}
fun main(args: Array<String>) {
val coffee = DaggerCoffeeShop.builder().build()
coffee.maker().brew()
}
我们注意到转换到 Kotlin 时注解代码几乎没有发生改变。 接下来将介绍构建脚本(build script)中需要修改的部分。
在 Java 中需要指定 Dagger 作为 annotationProcessor(或 apt)依赖:
dependencies {
...
annotationProcessor "com.google.dagger:dagger-compiler:$dagger-version"
}
apply plugin: ‘kotlin-kapt‘
dependencies {
...
kapt "com.google.dagger:dagger-compiler:$dagger-version"
}
ButterKnife
ButterKnife可以直接将view和变量进行绑定从而免去调用findViewById。
另外,Kotlin Android 扩展插件(Android Studio 内置)具有同样的效果:使用简洁明了的代码替换findViewByid。 除非现在你正在使用 ButterKnife 而且没有迁移计划,那么前者非常值得尝试。
在 Kotlin 中使用 ButterKnife 与 Java 中完全一致。 在 Gradle 构建脚本的修改如下,后面将重点介绍代码部分的差异。
在 Gradle 依赖中添加 kotlin-kapt 插件,并使用 kapt 替代 annotationProcessor。
apply plugin: ‘kotlin-kapt‘
dependencies {
...
compile "com.jakewharton:butterknife:$butterknife-version"
kapt "com.jakewharton:butterknife-compiler:$butterknife-version"
}
让我门看看发生了什么变化。 在 Java 中使用注解将变量与之对应的 view 进行绑定:
@BindView(R2.id.title) TextView title;
@BindView(R2.id.title)
lateinit var title: TextView
lateinit 修饰符允许声明非空类型,并在对象创建后(构造函数调用后)初始化。 不使用 lateinit 则需要声明可空类型并且有额外的空安全检测操作。
使用 ButterKnife 注解可以将方法设置为监听器:
@OnClick(R2.id.hello)
internal fun sayHello() {
Toast.makeText(this, "Hello, views!", LENGTH_SHORT).show()
}
hello.setOnClickListener {
toast("Hello, views!")
}
Data Binding
使用 Data Binding 开源库能够让开发者以更简洁的方式将应用程序数据与布局界面进行绑定。
查看完整示例。
和使用 Java 一样,开发者需要在 gradle 文件中添加并激活配置。
android {
...
dataBinding {
enabled = true
}
}
apply plugin: ‘kotlin-kapt‘
dependencies {
kapt "com.android.databinding:compiler:$android_plugin_version"
}
<data>
<variable name="data" type="org.example.kotlin.databinding.WeatherData"/>
</data>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@{data.imageUrl}"
android:contentDescription="@string/image" />
class MainActivity : AppCompatActivity() {
// ……
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)binding.data = weather
//等同于
binding.setData(weather)}
}
<Button
android:text="@string/next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startOtherActivity" />
class MainActivity : AppCompatActivity() {
// ……
fun startOtherActivity(view: View) = startActivity<OtherActivity>()
}
startActivity<OtherActivity>("KEY" to "VALUE").
请注意,与其在 xml 中声明 lambda 表达式,不如直接使用代码绑定相关动作:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> presenter.onSaveClick(task)}" />
// 用 Kotlin 代码写的相同逻辑
button.setOnClickListener { presenter.onSaveClick(task) }
DBFlow
DBFlow 是一个用于简化数据库交互的SQLite开源库。 它非常之依赖于注解处理。
查看 DBFlow 配置向导。
查看完整示例程序。
使用 kapt 配置 Kotlin 依赖:
apply plugin: ‘kotlin-kapt‘
dependencies {
kapt "com.github.raizlabs.dbflow:dbflow-processor:$dbflow_version"
compile "com.github.raizlabs.dbflow:dbflow-core:$dbflow_version"
compile "com.github.raizlabs.dbflow:dbflow:$dbflow_version"
}
若您的项目中已在使用 DBFlow,可以安全地将在项目中引入 Kotlin。 并且逐步地将代码转换为 Kotlin(确保每次编译通过)。 转换后的代码与 Java 并无明显差异。 例如,对表的声明和在 Java 中仅有小小的区别,属性声明时必须显示的指定默认值:
@Table(name="users", database = AppDatabase::class)
class User: BaseModel() {
@PrimaryKey(autoincrement = true)
@Column(name = "id")
var id: Long = 0
@Column
var name: String? = null
}
@Table(database = KotlinDatabase::class)
data class User(@PrimaryKey var id: Long = 0, @Column var name: String? = null)
dependencies {
compile "com.github.raizlabs.dbflow:dbflow-kotlinextensions:$dbflow_version"
}
Auto-Parcel
Auto-Parcel 使用 @AutoValue 的注解为类文件自动生成 Parcelable 对应方法和值。
同样的,gradle 文件中也需要使用 kapt 作为注解处理器来处理 Kotlin 文件:
apply plugin: ‘kotlin-kapt‘
dependencies {
...
kapt "frankiesardo:auto-parcel:$latest-version"
}
对 Kotlin 类文件添加 @AutoValue 注解。 下方的示例展示转换后的 Address 类以及自动生成相应的 Parceable 实现:
@AutoValue
abstract class Address : Parcelable {
abstract fun coordinates(): DoubleArray
abstract fun cityName(): String
companion object {
fun create(coordinates: DoubleArray, cityName: String): Address {
return builder().coordinates(coordinates).cityName(cityName).build()
}
fun builder(): Builder = `$AutoValue_Address`.Builder()
}
@AutoValue.Builder
interface Builder {
fun coordinates(x: DoubleArray): Builder
fun cityName(x: String): Builder
fun build(): Address
}
}
由于 Kotlin 中没有 static 方法,因此相应的方法会在 companion object中生成。 如果仍然需要从 Java 中调用这些方法,需要添加@JvmStatic注解。
如果调用 Java 的类或方法恰好在 Kotlin 中是保留字,可以使用反引号(`)作为转义字符,比如调用上例中生成类的`$AutoValue_Address`。以上所有经过转换的代码与原生 Java 代码非常相似。
评论(0)