使用Kotlin进行Android开发

JaysonBcf 8年前
   <h2>What is Kotlin</h2>    <p>Kotlin,原意是在俄罗斯的一个<a href="/misc/goto?guid=4959637305649146460" style="color:rgb(66,139,202); text-decoration:none">小岛</a>,JetBrain在2011年推出了以这个来命名的一个运行在JVM上的语言, 看上去有点类似C#和Scala的结合,并且同为静态类型,作为一门JVM上的语言,可以轻松兼容Java,并且整个语言设计的非常轻量。目前的版本为<code>0.12.200</code>,尚未发布正式版。</p>    <p>Kotlin的下载和配置在其<a href="/misc/goto?guid=4959637305728178022" style="color:rgb(66,139,202); text-decoration:none">官网</a>上有,在这里就不再赘述了,值得一提的是,作为JetBrains家出品的语言,自家的IDEA当然全力支持!</p>    <h2>基本语法介绍</h2>    <p>Kotlin的语法非常简洁,熟悉Java或者Scala的人都可以快速上手:</p>    <p>函数声明:</p>    <pre>  <code class="language-kotlin">fun foo(va: Int): Int {      return 1  }</code></pre>    <p>也可以单行声明:</p>    <pre>  <code class="language-kotlin">fun foo(va: Int): Int = 1</code></pre>    <p>lambda当然也是支持的:</p>    <pre>  <code class="language-kotlin">var c = {foo: Int -> println(foo)}</code></pre>    <p>Kotlin中的函数是一等对象,自然支持高阶函数:</p>    <pre>  <code class="language-kotlin">var c = {foo: Int -> println(foo)}  fun fooTest(func: (Int)->()) = println("I'm Groot")      fooTest(c)</code></pre>    <p> </p>    <p>类与接口</p>    <p>类可以这样进行声明:</p>    <pre>  <code class="language-kotlin">class Bar(var b: Int): Foo() {      var c = 1      init {          println("class initializer")      }        constructor(): this(1) {          println("secondary constructor")      }  }</code></pre>    <p>Bar类在这里继承了Foo类,Bar类有两个构造函数,直接在Bar类头的是primary constructor,另外一个构造函数使用<code>constructor</code>关键字定义,注意必须要先调用primary constructor,另外,<code>init</code>标明的是class initializer,每个构造函数都会首先调用class initializer里面的代码,再调用构造函数</p>    <p>Inner class:</p>    <pre>  <code class="language-kotlin">class Outer {      class Inner {            }  }</code></pre>    <p>Kotlin同样支持嵌套的内部类,不过和Java不一样的是,Kotlin的内部类不会默认包含一个指向外部类对象的引用,也就是说,Kotlin中所有的内部类默认就是静态的,这样可以减少很多内存泄露的问题。另外,如果需要在内部类中引用外部类对象,可以在Inner类的声明前加上<code>inner</code>关键字,然后在Inner类中使用标记的<code>this</code>:<code>this@Outer</code>来指向外部类对象</p>    <p>Singleton:</p>    <pre>  <code class="language-kotlin">object Single {      var c = 1        fun foo() = println("foo")  }</code></pre>    <p>Kotlin中使用<code>object</code>关键字声明一个singleton对象,后面这里的方法就可以直接使用<code>Single.foo()</code>来调用了</p>    <p>Interface:</p>    <pre>  <code class="language-kotlin">interface Interface {      fun foo() {          println(1)      }      fun bar()  }</code></pre>    <p>Kotlin中的interface,跟其他语言的<code>trait</code>非常像,而且也可以带有默认的实现方法,并且不允许通过属性来维护状态。事实上,在上个版本中,interface的原来名称是<code>trait</code>,而在M12现在这个版本中又改成了interface而已</p>    <p> </p>    <p>Null safe and Smart type cast</p>    <p>Null safe:</p>    <p>在Kotlin中,严格区分了nullable和非nullable对象,甚至在编译期解决了不少潜在的空指针问题:</p>    <p>我们先来看下普通的变量声明</p>    <pre>  <code class="language-kotlin">var c: String = "12123"</code></pre>    <p>这里声明了一个String对象,其值为"12123",我们可以正常的使用这个对象的成员方法:<code>c.length()</code></p>    <p>但是,如果在初始化的时候,变量c为空的话,这样声明就是错误的,会编译不过:</p>    <pre>  <code class="language-kotlin">var c: String = null</code></pre>    <p>正确的声明应该是这样:</p>    <pre>  <code class="language-kotlin">var c: String? = null</code></pre>    <p>这里在<code>String</code>后面加多了一个问号,表明这里是一个Nullable的对象,说明这个变量在使用的过程中可能为空,而且,在调用这个变量的成员的时候,必须要使用这种语法:<code>c?.length()</code>,在调用的时候添加了一个问号,表明,如果<code>c</code>为空的时候,<code>length()</code>这个方法就不会调用。coffe-script也有类似的,这种语法糖减少了很多平时用到的Null-checked,简化了代码,而且从编译器开始介入null-checked,大大减少了潜在的<code>NullPointerException</code>,而事实上,null的确也是一个<a href="/misc/goto?guid=4958829387358832082" style="color:rgb(66,139,202); text-decoration:none">billion dollar mistake</a></p>    <p>常年进行如此的调用语法常常会很恼人,因此在你进行显式的Null-checked的时候,Kotlin的编译器会认为后续的调用已经无需进行Null-checked,可以直接调用了:</p>    <pre>  <code class="language-kotlin">if (c != null) {      c.length()  }</code></pre>    <p>Smart type cast</p>    <p>在Kotlin中,进行强制类型转换可以使用<code>as</code>关键字,但有可能会抛出异常,因此,Kotlin引入了smart type cast:</p>    <pre>  <code class="language-kotlin">if (c is String) {      c.length()  }</code></pre>    <p>在上面的例子中,如果<code>c</code>是一个String对象,则在if块中,可以直接使用String的方法,编译器会智能的帮你识别出c在if-blcok里面是一个String对象</p>    <p>Pattern Matching</p>    <p>Kotlin在一定程度上支持了一些FP的特性,包括强大的Pattern Matching,在Kotlin中可以使用<code>when</code>关键字:</p>    <pre>  <code class="language-kotlin">var x = 3  when (x) {      1 -> print("x == 1")      2 -> print("x == 2")      in 1..10 -> print("x is in the range")      !in 10..20 -> print("x is outside the range")      is Int -> println("is int")      else -> { // Note the block        print("x is neither 1 nor 2")      }  }</code></pre>    <p>Function Extension</p>    <p>在Java中我们经常需要给系统的类添加一些实用的方法,但苦于不能直接扩展,于是就有了各种的xxxUtils类,导致代码非常恶心,但是在Kotlin中,我们可以直接扩展库里面类的方法,通过function extension:</p>    <pre>  <code class="language-kotlin">fun String.fucker() {      println("a fucker")  }</code></pre>    <p>上面给<code>String</code>类添加了一个fucker方法,我们可以直接使用:</p>    <pre>  <code class="language-kotlin">"123123".fucker()</code></pre>    <p>这大大的减少了我们写xxxUtils类的必要性</p>    <h3>配置使用Kotlin进行Android开发</h3>    <p>使用Kotlin开发Android app的配置非常简单,按照<a href="/misc/goto?guid=4959637305978354795" style="color:rgb(66,139,202); text-decoration:none">官方给出的配置即可</a>,直接在Gradle的配置文件build.gradle中添加一个依赖:</p>    <pre>  <code class="language-kotlin">compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"</code></pre>    <p>然后添加Kotlin插件的使用:</p>    <pre>  <code class="language-kotlin">apply plugin: 'kotlin-android'</code></pre>    <p>进行一次Gradle Sync之后,就可以直接在项目使用Kotlin编写代码了,另外,如果安装了Intellij的Kotlin插件,可以选择 <code>Tools->Kotlin->Configure Kotlin in Project</code>,就可以自动进行上述的配置,一步到位</p>    <p>我写了一个简单的Demo app放到了Github上,有兴趣可以看下使用Kotlin开发android app具体是怎样的:<a href="/misc/goto?guid=4959637306066139915" style="color:rgb(66,139,202); text-decoration:none">Demo地址</a></p>    <h2>对于dex方法数目的影响</h2>    <p>dex有个65535方法数的限制,这对Android开发造成了很大的影响,在使用Kotlin进行android app开发的时候,需要将Kotlin的标准库打包进入apk中,这意味着如果标准库过大,对分包会造成很大的限制(因为这必须得打包在主dex中),所幸的是,Kotlin的哲学是“Java中有的,就尽量复用,不再自行创造一套”,使得整个Kotlin的标准库非常小,我们可以简单将Kotlin的标准库和其他比较常用库进行一下对比:</p>    <table border="1" cellpadding="5" style="border-collapse:collapse; border-spacing:0px; color:rgb(51,51,51); font-family:helvetica neue,helvetica,arial,sans-serif; font-size:14px; line-height:25.2px; max-width:100%">     <tbody>      <tr>       <td>包名</td>       <td>android-support-v13.jar</td>       <td>android-support-v4.jar</td>       <td>android-support-v7-appcompat.jar</td>       <td>guava-18.0.jar</td>       <td>scala-library-2.12.0-M1.jar</td>       <td>kotlin-stdlib-0.12.213.jar</td>      </tr>      <tr>       <td>方法数</td>       <td>8219</td>       <td>8118</td>       <td>4624</td>       <td>14833</td>       <td>51248</td>       <td>7228</td>      </tr>     </tbody>    </table>    <p><br> 可以看出来Kotlin的标准库相当小,只有7000多个方法,比support-v13和support-v4还小,这体现了Kotlin的设计哲学之一:"100% interoperable with Java",基本上Java已经有的,Kotlin会尽量复用。而对比来看,同样是JVM上的语言,我们也可以选择使用Scala来进行Android开发,但Scala标准库有5万多个方法,全部打包进主dex中,很容易就导致app爆主dex了。所以综合来看,轻量形的Kotlin还是相当适合进行Android开发的。</p>    <h2>Project Anko</h2>    <p><a href="/misc/goto?guid=4958968980632722486" style="color:rgb(66,139,202); text-decoration:none">Anko</a> 是JetBrains推出的一个简化Android开发的库,同样由Kotlin来编写,主要的革命在于,声明UI的方式,完全抛弃了xml的使用,使用Anko,声明UI是这样做的:</p>    <pre>  <code class="language-kotlin">override fun onCreate(savedInstanceState: Bundle?) {      super.onCreate(savedInstanceState)      val customStyle = { v: Any ->          when (v) {              is Button -> v.textSize = 26f              is EditText -> v.textSize = 24f          }      }        verticalLayout {            padding = dip(34)          imageView(android.R.drawable.ic_menu_manage).layoutParams {              margin = dip(16)              gravity = Gravity.CENTER          }             val name = editText {               hintResource = R.string.name          }          val password = editText {              hintResource = R.string.password              inputType = TYPE_CLASS_TEXT or TYPE_TEXT_VARIATION_PASSWORD          }            button("Log in") {              onClick {                  tryLogin(name.text, password.text)              }          }      }.style(customStyle)  }</code></pre>    <p>你没看错,的确是在Activity类的onCreate方法中直接声明UI的布局。</p>    <p>Anko看起来像是使用了一种类似DSL的方式声明了界面的UI,这里主要是使用了Kotlin的其中两个特性:</p>    <ul>     <li>Function Extension,Anko扩展了Activity类,提供了额外的方法和属性</li>     <li>Kotlin在调用函数的时候,如果最后一个参数为函数的话,则可以直接使用Lambda,并省略括号</li>    </ul>    <p>因此这里声明布局的方式,其实全是Kotlin的原生代码,鹅妹子嘤!这样做有显然的好处:</p>    <ul>     <li>由于实际上全是由代码来布局,省去了解析xml的时间</li>     <li>xml本身有许多缺点,例如不可重用,非类型安全等,使用代码布局的话,我们可以很容易的就解决这个问题了</li>    </ul>    <p> </p>    <p>来自:http://blog.csdn.net/chaoyu168/article/details/52047687</p>    <p> </p>