转载

使用 Kotlin 和 Anko 的安卓开发入门

使用 Kotlin 和 Anko 的安卓开发入门

我将会说这会像这个样子……

安卓困在了 Java 6 的炼狱中。

使用 Kotlin 和 Anko 的安卓开发入门

当我刚开始开发安卓的时候,我是一个多年的 C# 工程师。我发现安卓缺少泛型支持(和 Java 的泛型比较而言),没有 lambda 表达式, 我认为在一个语言中应该有的东西这里却有着非常笨拙的语法。8 年后,我仍然在写着非常繁琐的 Java 6。Java 8 已经出来一段时间了,在不改变二进制代码的情况下,如果能使用它的一些功能就太棒了!(这就是说,我非常感谢 retrolambda 。)但是不幸的是,谁知道 Java 8 什么时候会到来呢。

谢天谢地,安卓开发看起来有希望了: Kotlin 。

使用 Kotlin 和 Anko 的安卓开发入门

Kotlin 是 JetBrains 公司提供的安卓应用开发的全新 JVM-compatible 的语言。如果你从来没有听说过这个语言,我强烈推荐你看看 Michael Pardo’s 关于 Kotlin 的演讲 来自 Droidcon NYC 。而且,应用局部布局视图可用通过 Anko 来创建,这是一个用 Kotlin 写的安卓开发的 DSL (Domain-Specific Language) 组件。你可以对 Anko 有一个基本的了解 这里 。

Kotlin,作为一个开发语言相对于 Java 6 来说是全新的。当你习惯了它的语法以后,你会注意到它比 Java 6 要简洁很多。因为 Kotlin 是 JVM-compatible 的,它编译成的 JVM 二进制代码能被安卓理解。

重要提示:这篇文章假设你已经有了对于基本的 Kotlin 和 Anko 的理解。

在安卓项目里面使用 Kotlin

作为一个新的知识,你应该想试试 Kotlin,但是你还不想深入理解整个项目。在 Kotlin 和 Android Studio 的帮助下,你可以在你的应用里面同时使用 Java 和 Kotlin。我推荐从一个屏幕,一个功能,或者一个简单的定制的空间开始,使用 Kotlin 看看如何编写它们。慢慢地往你的代码中集成 Kotlin,这样可以让你对这个语言有一个测试,然后允许你保持应用的代码不被改动。

幸运的是集成 Kotlin 到现有的安卓应用里面是十分容易的,只需要使用免费的 Android Studio 的 Kotlin 插件。一开始,你需要安装插件。打开 Android Studio 然后选择 Configure > Plugins 。如果你的屏幕下方看不见了,关闭你所有的项目然后 Welcome to Android Studio 窗口会自动出现。

使用 Kotlin 和 Anko 的安卓开发入门

然后选择 Install JetBrains Plugin 如下。

使用 Kotlin 和 Anko 的安卓开发入门

现在搜索 Kotlin 然后按如下步骤安装 Kotlin 插件。Kotlin 主插件就会出现在你的安卓扩展里面。

使用 Kotlin 和 Anko 的安卓开发入门

你现在已经可以开始创建你的第一个用 Kotlin 实现的功能了!

应用

我打算创建一个简单的 to-do 列表的应用。主屏幕有一个 to-do 的待办事项如下:

使用 Kotlin 和 Anko 的安卓开发入门

用户通过点击 FAB (Floating Action Button) 来增加一个 to-do。编辑 to-do, 你需要点击 to-do 本身。这会加载一个编辑界面。编辑界面是我用 Kotlin 和 Anko 来编写的。

什么是 Anko?

Anko 是一个 DSL (Domain-Specific Language), 它是用 Kotlin 写的安卓插件。长久以来,安卓视图都是用 XML 来表述布局的。这个 XML 常常在你的应用里面有多个复制的版本,而且不能重用(有时候能,通过 includes)。在运行的时候,XML 被转换成 Java 表述,这很浪费 CPU 和电池。Anko 允许你能用 Kotlin 来编写视图,在任何的 Activity 或者 Fragment 里(或者一个 [AnkoComponent] (https://github.com/Kotlin/anko#ankocomponent) 里,这是一个表述视图的扩展 Kotlin 文件)。

这里是一个转换成 Anko 的简单 XML 文件。

XML

<LinearLayout     xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_height="match_parent"     android:layout_width="match_parent">      <EditText         android:id="@+id/todo_title"         android:layout_width="match_parent"         android:layout_heigh="wrap_content"         android:hint="@string/title_hint" />      <!-- Cannot directly add an inline click listener as onClick delegates implementation to the activity -->     <Button         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:text="@string/add_todo" />  </LinearLayout>

用 Anko 描述的同样的视图

verticalLayout {     var title = editText {         id = R.id.todo_title         hintResource = R.string.title_hint     }     button {         textResource = R.string.add_todo         onClick { view -> {                 // do something here                 title.text = "Foo"             }         }     } }

注意上面第一个的布局中的点击监听函数。因为这是 Kotlin,你可以访问其他的视图成员,比如 title 然后在点击监听函数里面使用它。

上手

使用这个 初学者的应用 你可以以一个空白的面板开始。(最终的代码在 这里 )。 这个应用有以下组件:

  • 一个 Activity ( MainActivity ) 作为应用的简单控制器。
  • 一个 RecyclerView 来展示第一屏上的 to-dos(TodosFragment)
  • 一个 Realm 数据库来存储 to-dos
  • 一个 Todo.java 表述 Realm 模型
  • 一个 RecyclerView 的 adapter

你现在用 Kotlin 和 Anko 来创建编辑屏。

创建 Kotlin 和 Anko 的应用

现在你已经安装了 Kotlin 扩展,你想用 Configure Kotlin in Project 来配置你的应用。在 Android Studio 里面,按下 CMD+SHIFT+A 来打开 action 查找对话框。输入 Kotlin 然后选择 Configure Kotlin in Project 如下:

使用 Kotlin 和 Anko 的安卓开发入门

在这之后,你的 build.gradle 文件会变成 kotlin-android ,并且作为最上层的配置文件,一个 Kotlin sourceSet 被添加了,然后 Kotlin 被加做了你的依赖。

然后你也想把 Anko 加做依赖。你的 build.gradle 文件看起来像这样:

apply plugin: 'com.android.application' apply plugin: 'kotlin-android'  android {     compileSdkVersion 23     buildToolsVersion "23.0.2"      defaultConfig {         applicationId "com.donnfelker.kotlinmix"         minSdkVersion 16         targetSdkVersion 23         versionCode 1         versionName "1.0"     }     buildTypes {         release {             minifyEnabled false         }     }     packagingOptions {         exclude 'META-INF/services/javax.annotation.processing.Processor'     }     sourceSets {         main.java.srcDirs += 'src/main/kotlin'     } }  dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     testCompile 'junit:junit:4.12'      // Kotlin     compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"      // 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      compile 'com.android.support:appcompat-v7:23.1.1'     compile 'com.android.support:design:23.1.1'     compile 'io.realm:realm-android:0.87.1'     compile 'com.github.thorbenprimke:realm-recyclerview:0.9.12'     compile 'com.jakewharton:butterknife:7.0.1'     compile 'com.android.support:support-v4:23.1.1' } buildscript {     ext.kotlin_version = '1.0.0'     repositories {         mavenCentral()     }     dependencies {         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"     } } repositories {     mavenCentral() }

现在你可以增加编辑屏幕了。

用 Kotlin 增加一个 Fragment

如果 src/main/kotlin/com.donnfelker.kotlinmix/ 目录不存在,创建它。你会注意到 kotlin 文件夹变蓝了,这意味着它是一个源文件目录了。

右键点击 /src/main/kotlin/com.donnfelker.kotlinmix/ 目录,选择 New > Kotlin File/Class ,然后重命名为 EditFragment 。新文件被创建了,并且只包含包声明。

拷贝下面的代码到 EditFragment 文件里。

package com.donnfelker.kotlinmix  import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.EditText import com.donnfelker.kotlinmix.models.Todo import io.realm.Realm import org.jetbrains.anko.* import org.jetbrains.anko.support.v4.UI import org.jetbrains.anko.support.v4.find import java.util.*  class EditFragment : Fragment() {      val TODO_ID_KEY: String = "todo_id_key"      val realm: Realm = Realm.getDefaultInstance()      var todo: Todo? = null      companion object {         fun newInstance(id: String): EditFragment {             var args: Bundle = Bundle()             args.putString("todo_id_key", id)             var editFragment: EditFragment = newInstance()             editFragment.arguments = args             return editFragment         }          fun newInstance(): EditFragment {             return EditFragment()         }     }      override fun onActivityCreated(savedInstanceState: Bundle?) {         super.onActivityCreated(savedInstanceState)          if(arguments != null && arguments.containsKey(TODO_ID_KEY)) {             val todoId = arguments.getString(TODO_ID_KEY)             todo = realm.where(Todo::class.java).equalTo("id", todoId).findFirst()             val todoTitle = find<EditText>(R.id.todo_title)             todoTitle.setText(todo?.title)             val todoDesc = find<EditText>(R.id.todo_desc)             todoDesc.setText(todo?.description)             val add = find<Button>(R.id.todo_add)             add.setText(R.string.save)         }     }      override fun onDestroy() {         super.onDestroy()         realm.close()     }      /**      *  A private function to create a TODO item in the database (Realm).      *      *  @param title the title edit text.      *  @param desc the description edit text.      */     private fun createTodoFrom(title: EditText, desc: EditText) {         realm.beginTransaction()          // Either update the edited object or create a new one.         var t = todo?: realm.createObject(Todo::class.java)         t.id = todo?.id?: UUID.randomUUID().toString()         t.title = title.text.toString()         t.description = desc.text.toString()         realm.commitTransaction()          // Go back to previous activity         activity.supportFragmentManager.popBackStack();     }  }

上面的例子有一些方法: newInstanceonActivityCreatedonDestroy ,和 createTodoFromcreateTodoFrom 接收两个 EditText 组件作为参数,或者用作创建新的 Todo 或者用作更新一个已存在的条目,所有的事情用一行代码搞定。

var t = todo?: realm.createObject(Todo::class.java)

这会检查看看当前的 todo 值是不是为 null。如果是的,它会创建一个新的 Todo 实例。如果不为 null,它会使用一个本地的作用域的实例。这个本地作用域的实例会在文件开始的 onActivityCreated 方法中实例化。

onActivityCreated 里面,fragment 的参数会被检查。如果他们不是 null, Todo 的 id 会从 intent extras 中解析出来,然后从 Realm 中得到 Todo 对象。 todo 条目已经实例化了,标示着 Todo 对象可以被编辑。这时候,视图会被相应的值更新。

用 Anko 增加视图

你现在可能意识到我们的 Fragment 里面还没有视图。为了增加一个视图,拷贝粘贴下面的代码到 fragment:

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {     return UI {         verticalLayout {             padding = dip(30)             var title = editText {                 id = R.id.todo_title                 hintResource = R.string.title_hint             }              var desc = editText {                 id = R.id.todo_desc                 hintResource = R.string.description_hint             }             button {                 id = R.id.todo_add                 textResource = R.string.add_todo                 onClick { view -> createTodoFrom(title, desc) }             }         }     }.view }

这里的 Anko 代码创建了一个垂直方向的线性布局( verticalLayout )。在 verticalLayout 代码段内部,创建了三个安卓的控件 - 两个 editText 视图和一个 button 视图。这里视图的属性都在一行里面设置好了。按钮控件的定义有些有意思的地方。按钮有一个点击监听函数是定义在视图定义文件里面的。在定义按钮之前,有两个参数 titledesc 的方法 createTodoFrom 已经被调用了。最后,通过在 AnkoContext ( UI 类)上调用 view 属性来返回视图。

这里的 id s 被设置为 R.id.<id_name> 。这些 id s 需要手工在一个加做 ids.xml 的文件里创建,这个文件放在 app/src/main/res/values/ids.xml 。如果这个文件不存在就创建它。文件内容如下:

<?xml version="1.0" encoding="utf-8"?> <resources>     <item name="todo_title" type="id" />     <item name="todo_desc" type="id" />     <item name="todo_add" type="id" /> </resources>

这个 ids.xml 文件定义了所有能够被安卓应用引用到的各种视图的 id s。

Java 和 Kotlin 编译

现在,视图能在屏幕上显示了。唯一剩下的事情就是在用户点击一个条目的时候显示 Fragment。

打开 TodosFragment 然后在 onTodoClick 方法中增加下面的代码:

EditFragment editFragment = EditFragment.Companion.newInstance(task.getId());         getActivity().getSupportFragmentManager()                 .beginTransaction()                 .replace(R.id.content_main, editFragment, editFragment.getClass().getSimpleName())                 .addToBackStack(editFragment.getClass().getSimpleName())                 .commit();

这个 EditFragment 是使用纯 Kotlin 写的,你可以把它当作一个正常的 Java 对象在安卓代码的任何地方非常容易地调用它。

注意 EditFragment.Companion.newInstance 调用?这是必须的,因为 Kotlin 没有静态方法。所以,一个 伴随对象 是完成 Kotlin 中相似功能的必须品。

最后,你需要连接 FAB 来启动 fragment。在 FAB’s 的点击监听函数里面,在 MainActivity 里面,你需要增加下面的代码:

EditFragment editFragment = EditFragment.Companion.newInstance(); getSupportFragmentManager()     .beginTransaction()     .replace(R.id.content_main, editFragment, editFragment.getClass().getSimpleName())     .addToBackStack(editFragment.getClass().getSimpleName())     .commit();

编译和安装你的应用,然后点击 FAB。这会启动你的应用中的 Kotlin 部分。添加一个 to-do 然后点击 Add 。退回到 to-dos 的列表,点击一个 to-do 然后你可以编辑它。在 Kotlin 里面的按钮文字 EditFagment 会变成 ‘save’。更新 to-do 然后点击 save。

使用 Kotlin 和 Anko 的安卓开发入门

恭喜你,你现在有混合的 Java 和 Kotlin 了!:clap:

你现在用 Kotlin 创建了一个功能,而你剩下的应用依旧是用安卓中典型的 Java 来工作的。你可以继续在你的 Kotlin 开发的道路上前行或者在你需要它的时候再使用它。

你现在能够使用 Anko 作为你的 Kotlin 的视图机制了。如果你更喜欢 XML,你可以继续使用 XML 布局。例如,你可以把上面的 onCreateView 方法用下面的内容替换:

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {     return inflater?.inflate(R.layout.your_layout, container, false) }

这给你提供了使用 Kotlin 或者 Anko 的灵活性。

祝你的 Kotlin 旅程好运!

例子代码

原文  https://realm.io/cn/news/getting-started-with-kotlin-and-anko/
正文到此结束
Loading...