用Kotlin优雅地开发Android应用
创始人
2025-02-12 14:22:01
0次

写在前面

在之前的一篇文章,我们简单的知道了Kotlin这门新语言的优势,也接触了一些常见的语法及其简单的使用,相信你会对它有浓厚的兴趣,暂且理解为对它感兴趣吧,哈哈哈。那么,我们该如何在Android中应用这门新的语言呢?今天的这篇文章带你学习使用Kotlin开发Android应用,并对比我们传统语言Java,让你真真切切的感受到他的美和优雅。

配置

项目gradle文件

  1. apply plugin: 'com.android.application' 
  2.  
  3. apply plugin:'kotlin-android' 
  4.  
  5. apply plugin:'kotlin-android-extensions' 
  6.  
  7.   
  8.  
  9. dependencies { 
  10.  
  11.     classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.1' 
  12.  
  13. }  

app Gradle文件:

  1. compile 'org.jetbrains.kotlin:kotlin-stdlib:1.1.1' 
  2.  
  3. compile 'org.jetbrains.anko:anko-sdk25:0.10.0-beta-1'// sdk15, sdk19, sdk21, sdk23 are also available 
  4.  
  5. compile 'org.jetbrains.anko:anko-appcompat-v7:0.10.0-beta-1'  

Anko

通过上面的配置,你会发现引入的有anko的依赖。Anko是JetBrains开发的一个强大的库,说起JetBrains ,那就牛逼了,Kotlin语言是他们开发的,***的的开发工具intellij idea都是他们开发的,AS也是基于IDEA的。好了,言归正传,Anko是Kotlin官方开发的一个让开发Android应用更快速更简单的Kotlin库,并且能让我们书写的代码更简单清楚更容易阅读。它包括多个部分,如下

  1. Anko Commons: a lightweight library full of helpers for intents, dialogs, logging and so on; 
  2.  
  3. Anko Layouts: a fast and type-safe way to write dynamic Android layouts; 
  4.  
  5. Anko SQLite: a query DSL and parser collection for Android SQLite; 
  6.  
  7. Anko Coroutines: utilities based on the kotlinx.coroutines library  

那么接下来,我们就通过代码来理解Kotlin语言开发Android的优势所在。

再也不用findViewById

做过Android开发的人都知道,布局文件写的多了,findViewById也是一个很大的工作量,而且还要先声明变量,在findViewById然后再强转成我们的控件,使用方式一般如下

  1. TextView username; 
  2.  
  3. username=(TextView)findViewById(R.id.user); 
  4.  
  5.   
  6.  
  7. username.setText("我是一个TextView");  

有时候写的是不是想吐,可能有些人说现在不是有一些注解的库,如butterknife,当我们使用注解时可以不用findViewById了,使用方式如下

  1. @BindView(R.id.user) 
  2.  
  3. TextView username; 
  4.  
  5. username.setText("我是一个TextView");  

确实是这样,使用注解后确实给我们少了一些工作量,不过这依然没有最简单化,最简单的就是我们可以直接给id为user的控件直接赋值,或许你会感觉这有点不可思议。不过Kotlin确实做到了。我们可以直接这样写

  1. user.text="我是一个TextView" 

看到这你是不是有一种相见恨晚的感觉,太Tama的简洁了。user就是我们布局文件声明的id,.text就想当与setText()给,在Kotlin语言中,我们看不到了像Java中的set/get方法了。需要注意的是,当我们想这样使用的时候(不用findViewById,直接使用xml控件我们需要在gradle加入apply plugin: ‘kotlin-android-extensions’),需要加入下面一句代码

  1. //activity_login就是我们的布局 
  2.  
  3. import kotlinx.android.synthetic.main.activity_login.*  

Anko Layout

通常我们使用xml文件写我们的布局,但是他有一些缺点如不是类型安全,不是空安全,解析xml文件消耗更多的CPU和电量等等。而Anko Layout可以使用DSL动态创建我们的UI,并且它比我们使用Java动态创建布局方便很多主要是更简洁,它和拥有xml创建布局的层级关系,能让我们更容易阅读。

  1. verticalLayout { 
  2.  
  3.             val textView=textView("我是一个TextView") 
  4.  
  5.             val name = editText("EditText") 
  6.  
  7.             button("Button") { 
  8.  
  9.                 onClick { toast("${name.text}!") } 
  10.  
  11.             } 
  12.  
  13.         }  

我们在OnCreate方法中可以去掉setContentView,然后加入上面代码就可以显示如下图的效果,即一个垂直的线性布局中,放了一个TextView,一个EditText,和一个Button。并且Button中有一个点击事件,当点击时将EditText的内容

以toast显示。  

 

上面的代码是不是很简单易懂,当然,默认的控件并不能满足我们的需求,例如我们会更改字体的颜色及大小,会设置宽度和高度,会设置margin,padding值,那么该如何实行呢,当然也很简单,因为它的逻辑和xml书写布局是一个套路。例如以下实现

  1. val textView=textView("我是一个TextView"){ 
  2.  
  3.                 textSize = sp(17).toFloat() 
  4.  
  5.                 textColor=context.resources.getColor(R.color.red) 
  6.  
  7.             }.lparams{ 
  8.  
  9.                 margin=dip(10) 
  10.  
  11.                 height= dip(40) 
  12.  
  13.                 width= matchParent 
  14.  
  15.             }  

我想我不需要说明上面的代码,你就应该看得出控件实行的效果。因为它的属性和我们在xml设置属性的名字对应的。

在上面创建UI过程中,我们直接把创建UI的代码写在onCreate方法中了,当然,还有一种写法。我们创建一个内部类实行AnkoComponent接口,并重写createView方法,该方法返回一个View,也就是我们创建的布局。修改如下

  1. inner class UI : AnkoComponent { 
  2.  
  3.         override fun createView(ui: AnkoContext): View { 
  4.  
  5.            return with(ui){ 
  6.  
  7.                verticalLayout { 
  8.  
  9.                    val textView=textView("我是一个TextView"){ 
  10.  
  11.                        textSize = sp(17).toFloat() 
  12.  
  13.                        textColor=context.resources.getColor(R.color.red) 
  14.  
  15.                    }.lparams{ 
  16.  
  17.                        margin=dip(10) 
  18.  
  19.                        height= dip(40) 
  20.  
  21.                        width= matchParent 
  22.  
  23.                    } 
  24.  
  25.                    val name = editText("EditText") 
  26.  
  27.                    button("Button") { 
  28.  
  29.                         onClick { view -> 
  30.  
  31.                             toast("Hello, ${name.text}!") 
  32.  
  33.                         } 
  34.  
  35.                    } 
  36.  
  37.                } 
  38.  
  39.            } 
  40.  
  41.         } 
  42.  
  43.     }  

然后在onCreate方法中加一句代码,即可创建我们的布局页面了。如下

  1. UI().setContentView(this@LoginActivity) 

现在我们编译运行,发现效果和布局文件写的界面是一样的。但是它的性能是有优势的,其实吧并没有发觉性能优势。不管怎样,这种DSL确实便于阅读,也很容易上手,在上面的代码中,你可能注意到了dip(10),它表示将10dp转换为像素的意思,是Anko的扩展函数,说的扩展函数,如果阅读过Anko的源码我们发现里面大量的使用扩展函数,这也是Kotlin语言的优势之一。确实很强大,例如dip扩展(摘取View扩展)

  1. inline fun View.dip(value: Int): Int = context.dip(value) 
  2.  
  3. fun Context.dip(value: Int): Int = (value * resources.displayMetrics.density).toInt()  

在上面resources.displayMetrics.density和我们Java getResources().getDisplayMetrics().density是一个效果,不过看着你会不会感觉比Java书写舒服多了,反正我是这么感觉的。

在上面的我们给Button加了一个点击事件,我们发现它支持lambda表达式。我们想显示一个Toast,只需要toast(“内容”)就可以了,是不是又很简洁。其实它也是扩展函数,实现

  1. inline fun AnkoContext<*>.toast(message: CharSequence) = ctx.toast(message) 
  2.  
  3. fun Context.toast(message: CharSequence) = Toast.makeText(this, message, Toast.LENGTH_SHORT).show()  

当然创建dialog依然也很简单,如下

  1. alert ("我是Dialog"){ 
  2.  
  3. yesButton { toast("yes")} 
  4.  
  5. noButton { toast("no")} 
  6.  
  7. }.show()  

真是越看越舒心,哈哈。再来一个强大而又很简单很简单很简洁的一段代码实现。

  1. doAsync { 
  2.  
  3.             //后台执行代码 
  4.  
  5.             uiThread { 
  6.  
  7.             //UI线程 
  8.  
  9.             toast("线程${Thread.currentThread().name}") } 
  10.  
  11.         }  

该段代码实现的就是AsyncTask 的效果,但是你应该发现它比Java的实现简洁多了,当然除非是色盲,要不然你会看出简洁的。

如果你使用Kotlin开发Android一段时间后,会发现它给我们减少了很多的代码量,当然更多的优势及用法需要我们自己去探索。相信经过探索后它会让你大吃一惊。

实现一个简单的登录界面

 

界面很简单,伪代码

  1.  
  2.  
  3.   
  4.  
  5.  
  6.  
  7.   
  8.  
  9.   
  10.  
  11.   
  12.  
  13.   
  14.  
  15.   
  16.  
  17.  
  18.  
  19.   
  20.  
  21.   
  22.  
  23.   
  24.  
  25.  
  26.  
  27.   
  28.  
  29.   

看着并不复杂的,那么xml实现的代码就不在这贴出了,如果你想看xml实现可看点击查,那么接下来来只看Anko在Kotlin代码中实现这个布局。

  1. lateinit var et_account: EditText 
  2.  
  3.     lateinit var et_password: EditText 
  4.  
  5.     inner class LoginUi : AnkoComponent { 
  6.  
  7.         override fun createView(ui: AnkoContext) = with(ui) { 
  8.  
  9.             verticalLayout { 
  10.  
  11.                 backgroundColor = context.resources.getColor(android.R.color.white) 
  12.  
  13.                 gravity = Gravity.CENTER_HORIZONTAL 
  14.  
  15.                 imageView(R.mipmap.ic_launcher).lparams { 
  16.  
  17.                     width = dip(100) 
  18.  
  19.                     height = dip(100) 
  20.  
  21.                     topMargin = dip(64) 
  22.  
  23.                 } 
  24.  
  25.   
  26.  
  27.                 linearLayout { 
  28.  
  29.                     gravity = Gravity.CENTER_VERTICAL 
  30.  
  31.                     orientation = HORIZONTAL 
  32.  
  33.                     backgroundResource = R.drawable.bg_frame_corner 
  34.  
  35.                     imageView { 
  36.  
  37.                         image = resources.getDrawable(R.mipmap.ic_username) 
  38.  
  39.                     }.lparams(width = wrapContent, height = wrapContent) { 
  40.  
  41.                         leftMargin = dip(12) 
  42.  
  43.                         rightMargin = dip(15) 
  44.  
  45.                     } 
  46.  
  47.                     et_account = editText { 
  48.  
  49.                         hint = "登录账户" 
  50.  
  51.                         hintTextColor = Color.parseColor("#666666") 
  52.  
  53.                         textSize = 16f 
  54.  
  55.                         background = null 
  56.  
  57.                     } 
  58.  
  59.                 }.lparams(width = dip(300), height = dip(40)) { 
  60.  
  61.                     topMargin = dip(45) 
  62.  
  63.                 } 
  64.  
  65.   
  66.  
  67.                 linearLayout { 
  68.  
  69.                     orientation = HORIZONTAL 
  70.  
  71.                     backgroundResource = R.drawable.bg_frame_corner 
  72.  
  73.                     gravity = Gravity.CENTER_VERTICAL 
  74.  
  75.                     imageView { 
  76.  
  77.                         image = resources.getDrawable(R.mipmap.ic_password) 
  78.  
  79.                     }.lparams { 
  80.  
  81.                         leftMargin = dip(12) 
  82.  
  83.                         rightMargin = dip(15) 
  84.  
  85.                     } 
  86.  
  87.                     et_password = editText { 
  88.  
  89.                         hint = "登录密码" 
  90.  
  91.                         hintTextColor = Color.parseColor("#666666") 
  92.  
  93.                         textSize = 16f 
  94.  
  95.                         background = null 
  96.  
  97.                     } 
  98.  
  99.                 }.lparams { 
  100.  
  101.                     width = dip(300) 
  102.  
  103.                     height = dip(40) 
  104.  
  105.                     topMargin = dip(10) 
  106.  
  107.   
  108.  
  109.                 } 
  110.  
  111.   
  112.  
  113.                 button("登录") { 
  114.  
  115.                     gravity = Gravity.CENTER 
  116.  
  117.                     background = resources.getDrawable(R.drawable.bg_login_btn) 
  118.  
  119.                     textColor = Color.parseColor("#ffffff") 
  120.  
  121.                     onClick { 
  122.  
  123.                         if (et_account.text.toString().isNotEmpty() && et_password.text.toString().isNotEmpty()) 
  124.  
  125.                             startActivity() else toast("请输入账户或者密码") 
  126.  
  127.                     } 
  128.  
  129.                 }.lparams(width = dip(300), height = dip(44)) { 
  130.  
  131.                     topMargin = dip(18) 
  132.  
  133.                 } 
  134.  
  135.                 linearLayout { 
  136.  
  137.                     orientation = HORIZONTAL 
  138.  
  139.                     gravity = Gravity.CENTER_VERTICAL 
  140.  
  141.                     checkBox("记住密码") { 
  142.  
  143.                         textColor = Color.parseColor("#666666") 
  144.  
  145.                         textSize = 16f 
  146.  
  147.                         leftPadding = dip(5) 
  148.  
  149.                     } 
  150.  
  151.                     textView("隐私协议") { 
  152.  
  153.                         textColor = Color.parseColor("#1783e3") 
  154.  
  155.                         gravity = Gravity.RIGHT 
  156.  
  157.                         textSize = 16f 
  158.  
  159.                     }.lparams(width = matchParent) 
  160.  
  161.                 }.lparams(width = dip(300)) { 
  162.  
  163.                     topMargin = dip(18) 
  164.  
  165.                 } 
  166.  
  167.   
  168.  
  169.                 textView("Copyright © Code4Android") { 
  170.  
  171.                     textSize = 14f 
  172.  
  173.                     gravity = Gravity.CENTER or Gravity.BOTTOM 
  174.  
  175.   
  176.  
  177.                 }.lparams { 
  178.  
  179.                     bottomMargin = dip(35) 
  180.  
  181.                     weight = 1f 
  182.  
  183.                 } 
  184.  
  185.             } 
  186.  
  187.         } 
  188.  
  189.     }  

看到上面的代码怎么样,看起来还不错吧,即使现在你不会写,但是你也能读懂它。在上面我们给登录按钮设置一个打开MainActivity的事件。startActivity的中写的是我们要跳转的Activity,如果给打开的界面传递参数,直接写在()中。例如我们将输入的账号和密码传到跳转的界面,则实现为

  1. startActivity("account" to et_account.text.toString(),"password" to et_password.text.toString()) 

其实Anko的强大之处远不止于此,值得我们细细品味。想更深入学习可以去GitHub Anko(https://github.com/Kotlin/anko),到此呢,本篇文章也就结束了,若在阅读时发现错误之处,欢迎指出,谢谢,Have a wonderful day. 

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
只需三步,让你掌握阿尔法路由器... 请参照以下阿尔法路由器设置方法,通过浏览器进入及设置宽带路由器。经过这三个步骤的设置,基本上能够熟悉...
如何更省钱? 近期特价热门硒鼓... 如今激光打印设备已经成为商务或企业的绝对主力办公设备,但采购者往往忽视了激光打印设备所用的耗材,相对...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...