13.6 配置 Kotlin 与 Anko 依赖
我们默认生成的 app 项目的 Gradle 配置文件build.gradle如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.easy.kotlin.mytodoapplication"
minSdkVersion 21
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:25.3.1'
testCompile 'junit:junit:4.12'
}
下面我们在 app 项目的build.gradle里面加上Kotlin 、Anko 、Realm、Butter Knife 等依赖。
13.6.1 Kotlin依赖
首先,启用插件kotlin-android
:
apply plugin: 'kotlin-android'
然后,添加构建脚本
buildscript {
}
我们使用 Kotlin 1.1.3版本。在构建脚本中添加kotlin-gradle-plugin依赖,使用 Kotlin 对应的版本号。
buildscript {
ext.kotlin_version = '1.1.3'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
在项目依赖里添加 Kotlin 标准库:
// Kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
13.6.2 添加 Kotlin 源代码目录
首先,我们在 src/main/下面新建一个 kotlin 目录,来存放 Kotlin源码。然后在 build.gradle 文件里的 android {}
配置里面添加Java的编译路径:
android {
...
sourceSets {
// += , 在main中创建kotlin文件夹, 用于存放kotlin代码
main.java.srcDirs += 'src/main/kotlin'
}
}
刚添加完毕,src/main/kotlin 还没有变成源码目录的蓝色,这个时候点击下图右上角的 Sync Now :
Gradle 同步完毕,即可看到kotlin 目录已经变成蓝色的源码目录了:
13.6.3 Anko依赖
在项目依赖里添加
// Anko
compile 'org.jetbrains.anko:anko-sdk15:0.8.2' // sdk19, sdk21, sdk23 are also available
compile 'org.jetbrains.anko:anko-support-v4:0.8.2' // In case you need support-v4 bindings
compile 'org.jetbrains.anko:anko-appcompat-v7:0.8.2' // For appcompat-v7 bindings
13.6.4 Realm依赖
compile 'io.realm:realm-android:0.87.1'
compile 'com.github.thorbenprimke:realm-recyclerview:0.9.12' // 在jitpack.io上
其中,Realm是一个轻量级的跨平台移动数据库引。Realm 简单易用,model 设计在代码中,更加易于维护,同时其性能也不错。在Android开发中,它可以替代 SQLite 和 ORM 框架。相比SQLite,Realm更快并且具有很多现代数据库的特性,比如支持JSON,流式api,数据变更通知,以及加密支持。
RecyclerView用于在有限的窗口展现大量的数据,相比ListView、GridView,RecyclerView标准化了ViewHolder,而且更加灵活,可以轻松实现ListView实现不了的样式和功能。我们使用的com.github.thorbenprimke:realm-recyclerview
依赖包在在jitpack.io上, 所以我们还需要配置一下仓库地址:
repositories {
mavenCentral()
maven { url "https://jitpack.io" }
}
提示:realm-recyclerview的 Github 地址
另外, Kotlin使用 Realm 还要加上注解处理的依赖库:
// kotlin使用realm的注解处理依赖库
kapt "io.realm:realm-annotations:0.87.1"
kapt "io.realm:realm-annotations-processor:0.87.1"
13.6.5 Butter Knife依赖
Butter Knife是基于注解处理方式工作:通过对代码注解自动生成模板代码。我们添加其依赖如下:
// Butter Knife,专门为Android View设计的绑定注解,专业解决各种findViewById
compile 'com.jakewharton:butterknife:8.7.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
Butter Knife主要是用来做Android视图的成员变量和属性的数据绑定。在开发过程中,我们通常要写大量的findViewById和点击事件,像初始view、设置view监听这样简单而重复的操作会显得比较繁琐。而我们有了 Butter Knife,就可以通过使用注解直接生成样板代码。例如,在 Java 中我们可以通过在字段上使用 @BindView 来替代 findViewById 的调用。上面的配置中的annotationProcessor 'com.jakewharton8.7.0'
就是来处理这些注解从而生成样板代码的。
@Bind(R.id.todo_item_todo_title)
public TextView todoTitle;
@Bind(R.id.todo_item_todo_content)
public TextView todoContent;
而在 Kotlin 中使用Butter Knife情况有些不同,需要作额外的配置。
如果在Kotlin中直接使用ButterKnife的注解方式的话,会出现空指针的异常,导致绑定失败。例如
@Bind(R.id.todos_recycler_view)
var realmRecyclerView: RealmRecyclerView? = null
运行会报错:
Caused by: kotlin.KotlinNullPointerException
at com.easy.kotlin.mytodoapplication.TodoListFragment.onResume(TodoListFragment.kt:43)
一般情况下,我们使用Kotlin集成 Java 生态的一些框架的时候,像 Spring Boot,JPA,Butter Knife,Realm等,都需要一些额外的插件或者依赖来“填充缝隙”(例如:all-open, kotterknife,realm-annotations等), 所谓Kotlin 与 Java 的无缝集成,很多时候并非Java 中怎么用,Kotlin就直接拿过来就怎么用,往往是要再添加一些插件或者额外的配置等。
那么要如何才能在Kotlin的环境中使用ButterKnife呢?
在早些时候,ButterKnife的作者已经帮我们想好解决方案了,那就是——KotterKnife,见名知意。KotterKnife的GitHub地址 。这个插件是建立在ButterKnife 7的基础上的。
下面我们配置一下在 Kotlin 中使用 Butter Knife 的依赖库 KotterKnife。
首先在repositories中添加KotterKnife的仓库地址(KotterKnife不在 Maven Center 仓库中,而是在oss.sonatype.org仓库中。这么多仓库,要是哪天能统一用一个就方便多了)。
repositories {
...
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
然后在dependencies里面添加依赖
dependencies {
...
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.jakewharton:kotterknife:0.1.0-SNAPSHOT'
}
采用这种方式的配置,我们的视图注入代码如下
val todoTitle: TextView by bindView(R.id.todo_item_todo_title)
val todoContent: TextView by bindView(R.id.todo_item_todo_content)
这样的代码看起来不是那么的优雅,还没有在 Java 中直接使用注解来的简单好看。同时要注意的是,如果使用 kotterknife 0.1.0 + butterknife:7.0.1 ,同时使用 Java 跟 Kotlin 混合编程的场景中使用 Butter Knife,发现配了KotterKnife 之后的 Java 的注解式写法就失效了。也就是说,如果我们上面添加了KotterKnife的依赖,那么 Java 代码中同时使用 Butter Knife 注解的地方会绑定失败。不过这个问题,在后面的新版本中已经解决。例如在butterknife 8.7.0中,我们可以直接添加下面的依赖项:
compile 'com.jakewharton:butterknife:8.7.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
kapt 'com.jakewharton:butterknife-compiler:8.7.0'
其中,annotationProcessor 'com.jakewharton8.7.0'
是 Java 的butterknife注解处理器。kapt 'com.jakewharton8.7.0'
是 Kotlin 的butterknife注解处理器(Kotlin Annotation processing tool,kapt)。
这样我们的代码就继续优雅简洁下去了:
@BindView(R.id.todo_item_todo_title)
lateinit var todoTitle: TextView
@BindView(R.id.todo_item_todo_content)
lateinit var todoContent: TextView
其中,lateinit 修饰符允许声明非空类型,并在对象创建后(构造函数调用后)初始化。 不使用 lateinit 则需要声明可空类型并且有额外的空安全检测操作。
当然,我们使用 Butter Knife 的同时,仍然可以使用原生的 findViewById :
class MainActivity : AppCompatActivity() {
var fab: FloatingActionButton? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById(R.id.toolbar) as Toolbar
setSupportActionBar(toolbar)
fab = findViewById(R.id.fab) as FloatingActionButton
// 添加日程事件
fab?.setOnClickListener { _ ->
...
hideFab()
}
}
fun hideFab() {
fab?.visibility = View.GONE
}
fun showFab() {
fab?.visibility = View.VISIBLE
}
}