初次尝试用Kotlin实现Android项目

 

   起这个文内标题的缘由很简单,就是对Kotlin抱有但愿——能使Android的开发更简洁、高效及安全。知道Kotlin是从简书的一篇短文,愈来愈以为将本身学习、实践的过程和想法总结成文字分享出来,无论文笔好坏,内容多少,若能抛砖引玉就足以。因此,感谢写了那么多精彩文章的大神,而我才刚从山脚启程。html

  项目源码放在Github上,感兴趣的朋友能够下载,欢迎送星和讨论。Demo运行的动态效果图以下:android

 

1. Kotlin在Android Studio中的环境配置git

  按照下面两篇文章的介绍操做,就能完成Kotlin在Android Studio中的环境配置(Eclipse就不推荐了),并能学习到基础语法和使用案例。若是有问题能够百度、谷歌或参考分享的项目源码中的Project及App的build.gradle设置,也能够留言你们一块儿讨论。github

  http://kotlinlang.org/docs/tutorials/kotlin-android.html
数据库

  http://kotlinlang.org/docs/tutorials/android-plugin.html
数组

  其实和引入普通插件相似,说简单点就是作两件事情:安全

  a 安装Kotlin插件;ide

  b Porject和App的build.gradle文件中添加引用;函数

  若是配置没问题了,在Studio工具栏的Code栏最下方会出现可将Java代码转为Kotlin代码的选择项:工具

  若是自己就是kt格式,那该选项就是灰色不可点击的。

 

2. Kotlin学习与编码总结

   开发环境OK以后,做为刚接触Kotlin的初学者,有两种选择:

  a 直接新建Android项目与Kotlin文件,在学习的同时从无到有得敲Kotlin代码;

  b 打开以前的Android项目,经过上述的转化工具先将有一个和若干Java文件转为Kotlin代码,经过阅读转化后的代码能够快速熟悉Android项目的Kotlin的代码;

  推荐从第二种方法开始,比较简单,并且通常在将Java代码转过来以后会有一些小错误或者警告,在修改的过程当中进步也是蛮大的。注明一下:Kotlin不仅是能在Android项目中替代Java,在其官网有详细的介绍。

  下面着重讲述一下由于Kotlin使得代码变得简洁、安全以及巧妙的几个点,这门新语言日渐成熟,不可能将其特色经过一两篇文章就能覆盖到。随着学习的深刻,以后会再进行补充。

2.1 text & setText()

1 text1.text = (Editable e)
1 text1.setText(CharSequence text)

  先来个简单的,text1是某布局中TextView组件的id。就这样一句代码,就能够完成文本的设置了,没有TextView类对象声明,不用调用findViewById()查找,是否是简洁好多。虽然说这中间有些步骤仍是须要Kotlin去默默处理,可是做为开发者,效率明显提高了。通常经常使用的是后面一种,由于CharSequence或者String的使用频率较高。可是Kotlin的简洁形式都趋向于obj.field,而不是setField()这样的方法,只不过这里将CharSequence转为Editable稍微麻烦了一点:

1 text1.text = Editable.Factory().newEditable(message)

2.2 @ & when () {}

1 login_image_sel.setOnClickListener(this@LoginFragment)
2 login_in.setOnClickListener(this@LoginFragment)
3 login_reg.setOnClickListener(this@LoginFragment)
4 login_out.setOnClickListener(this@LoginFragment)

  给四个id表明的组件设置点击监听,方法参数为View.OnClickListener,若是类已经继承了它并实现了其onClick()方法,那么直接写成表明本身的this便可。而@Name部分则是强调类名称(不写也不影响编译、运行),可是写上以后可读性更强了,能够说此@是写成开发者(本身或将来看代码的人)看的。

 1 override fun onClick(view: View) {
 2     val id = view.id
 3     when (id) {
 4         R.id.login_image_sel -> selectImageBtn()
 5         R.id.login_in -> loginInBtn()
 6         R.id.login_reg -> loginRegBtn()
 7         R.id.login_out -> loginOutBtn()
 8         else -> { }
 9     }
10 }

  第一行须要先解释,Java代码是这样的:

1 @Override
2 public void onClick(View view) {}

  有几个地方不一样:

  a @Override->override;

  b default->public,Kotlin默认的访问限制是public,因此能够省略;

  c void->: Unit,Kotlin无返回值能够省略,也能够写成: Unit,固然看我的习惯了;

1 override fun onClick(view: View): Unit {

  d View view->view: View,形参声明形式,具体的后面会再提到;

  Kotlin用when解放了switch,仔细琢磨一下能够发现,无论是代码形式和行数都简洁了很多。告别了原先Java的case、“:”、break及default,我认为最直接的好处是进入when以后,只会执行匹配项对应的"->"后面那一个分支,不用每次都要当心翼翼地想在哪加break。

2.3 var & val

1 val id = view.id

  接着上面的话题,来看一下变量的定义。看到上面这句代码,熟悉脚本语言的朋友会有亲切感,因此有时候以为Kotlin是在慢慢地将各门语言的优势结合起来。

  val和var对应,前者定义不可能变量,后者定义可改变量。这时候将Java的final拿出来最合适了,Kotlin中限定不可变的重担是由val来完成,它们限定的变量必须在声明时就赋值(类直接属性除外,具体的后面会再提到)。

  那么上面说到方法形参时(view: View),view后面有类型View,其实在声明变量时也是如此,来看几个例子:

1 var int1: Int = 1
2 var int2 = 2
3 var str3: String? = null
4 val str4: String? = null

  声明了四个变量:两个可变Int型,一个可变String型,一个不可变String型。既然不可变,那么在后面再次赋值时就会报错了:

1 int1 = 2
2 int2 = 3
3 str3 = "Hello"
4 str4 = "Kotlin"  //会标红线,鼠标移入显示"Val cannot be reassigned"

  实践过就会发现,Kotlin中不能再像Java那样声明变量了,好比:

1 var int3
2 var int4: Int

  这两种都是不行的,会提示"Property must be initialized or  be abstract"。

  再来看是类型后的那个问号(String? = null),它表示声明的变量是否容许为null。这要和另外一种状况区分开:声明变量的时候还不肯定其值是什么,解决方式能够是先赋一个不影响程序的值。好比:

1 var str3: String = "will be reassigned later"

  ": String"类型限定部分能够不加,编译器会自动推断,这样处理就没有“?”。

  那么有人疑问加“?”和不加的根本区别在哪?就在于程序运行过程当中对变量的赋值,若是给没有加“?”的变量赋值了null,程序就会异常。通常用在函数的形参中,好比定义的方法形参以下:

1 fun testNotNull(str: String) {}

  调用时传给形参str的值是不能为null的,这一特性很是有用。由于在大部分应用场景下均可以肯定须要的参数是否能够null,好比读取图像的路径不能为空,经过索引访问元素时列表不能为空等等。这不是说能够完美地解决由于null引发的异常,而是能够将异常的点提早,或者说变量容易发现与消除。至于在不一样场景怎么用,还得深刻研究,并非所有限定为NonNull就是最合适的。固然,非空限制在Java代码中也能够经过注解@NonNull来实现。

  “?”还有一个颇有用的地方是方法返回值:

1 fun getStringLength(obj: Any): Int? {
2     if (obj is String)
3         return obj.length // no cast to String is needed
4     return null
5 }

  在Java中声明为int返回值类型后,是不容许返回null值的,可能会在没有想要的结果时返回一个标记数值。而在Kotlin中只要检查返回值是否为null,若是不是则返回值就是但愿获得的结果。上面的代码还能够简写为:

1 fun getStringLength(obj: Any): Int? = if (obj is String) obj.length else null

  这里有一个新的知识,is的做用是判断obj是不是String类型实例应用,若是不是则直接返回null,Java是instanceof。

2.4 Any

  Any有点像Java中的Object,对象的祖先。直接上例子:

1 fun showLog(message: Any?) {
2     Log.i(LOG_TAG, message?.toString())
3 }

  这是在Utils文件中自定义的一个实现log的方法,形参message的类型时Any?,正好巩固一下上一条的概念。对于传入的实参,能够是null,也能够是任意类型的变量值;重点在于message后面的那个“?”,它会判断message是否为null,若是是则直接返回字串“null”,若是不是才去调用toString()方法。注意这里假设传入的实参对象继承或重写了toString(),不然可能会出错。

2.5 Custom View

  这里说的并非熟悉的自定义一个圆形View,而后在xml或者Java中进行使用,而是直接在代码中生成布局与组件,这又是Kotlin的一个优势。来看定制一个Dialog的代码:

 1 val dialog = Dialog(mContext, R.style.DialogNoTitle)
 2 dialog.setContentView(mContext.linearLayout {
 3     imageView {
 4         Utils.setImageToView(mContext, null, imageUri, this)
 5         onClick {
 6             dialog.dismiss()
 7         }
 8     }
 9 })
10 
11 dialog.show()

  代码中的Style和Utils部分能够在项目源码中查看,这里主要针对Kotlin定义布局部分。动态添加线性布局和一个图像组件只须要声明一个名称便可,分别为linearLayout和imageView。能够理解为包含的元素以{}为界,imageView属于linearLayout,而onClick {}和this则是属于imageView。测试发现,显示的Dialog默认就是居中的,想达到其余效果进行相应的调整便可。

2.6 Map

1 `object`.map {
2     var bulletinT = ReceiveBulletin(it.teacherName,
3             it.updatedAt,
4             it.bulletinContent,
5             it.bulletinImage?.fileUrl)
6     //do something
7 }
  这里的`object`能够是列表数据,也能够是数组等其余集合类型。map的做用就是遍历集合中的每个元素,对其在{}中进行处理,而每一个元素的临时名称为“it”。这样,是否是又能够不用看到for或者Iterator了。

2.7 Class

  2.3中提到过val声明的变量也能够先不赋值,这种状况会在Class的声明时出现:

1 class BulletinAdapter(private val mContext: Context,
2                       private val mBulletins: ArrayList<ReceiveBulletin>)
3         : RecyclerView.Adapter<BulletinAdapter.ViewHolder>() {}

  自定义了一个和RecyclerView结合使用的Adapter类,类的继承由Java的extends变成了冒号“:”,仿佛进入了C++的世界。

  类名后面居然跟了一个括号“()”,并且还多了那么多奇怪的参数,Kotlin的解释是这样写至关于快捷的构造函数。其实能够理解为primary constructor方法省略了名称,若是方法前有注解等特殊修改,那么名称“constructor”是不能省略的。之因此说类后面跟着的方法为primary,是由于在类中还能够实现secondary constructors,之后用到时再深挖吧。而init是在类对象构造时就会调用一次,仅此一次,因此能够做为类实例时的标记,好比打印log:

1 init {
2     Utils.showLog("Create a BulletinAdapter object")
3 }

  val就不解释了,传入的实参赋给形参变量后,在本类中是不容许改变的。可是集合有点特殊,好比从新给mContext赋值不行,可是给mBulletins经过add()方法添加元素是能够的,这里涉及到对象指向的地址和包含的元素问题,先不展开。

  添加了private访问限定符的目的和Java中相似,在类外不可见,即不容许在类外面对变量进行访问与更改。

2.8 if ()  {} else () {}

  以前2.2中when分支->后面代码都只有一句,若是有两句呢?先看看if else的情形:

1 if (position == itemCount - 1)
2     itemView.bulletin_divider.visibility = View.GONE
3 else
4     itemView.bulletin_divider.visibility = View.VISIBLE

  当分支下有多个语句时,必须将属于分支的全部代码都包含在{}中,不然会出现下面的else匹配不到if的错误,这点和Java中的也是相同的。最后提一下Kotlin中不推荐在语句后写分号“;”,写上也没错,只是给变量名下面画一条灰色的提醒而已。

 

3. 总结

3.1 项目介绍

  开头给出了项目源码下载地址和运行动态效果图,如今来进行简单的介绍。本身学习过程当中练手的不能叫作App,确切地应该叫Demo。

  Demo一共三个页面:消息接收、消息发送及用户信息。

  a 消息接收:打开程序时,会从云数据库中读取消息,若是有则加载,没有则显示提示信息(如稍后下拉刷新等);一条信息包括发送者头像、名称、发送时间、信息内容(文字或图片至少有其一);若是有图片内容,则点击后放大;消息的接收没有用户登陆要求;

  b 发送消息:只有注册并登陆的用户才能进行消息的发送;发送的内容至少要有文字或图片内容其中之一;

  c 用户信息:先进行注册,不能设置数据库中已存在的用户名,必定要选择头像,成功后通常会自动登陆;登录后才能进行注销操做;注销后才能进行再次登陆操做;

这里说的云数据库指的是项目中用到的免费的Bmob云平台,比较适合我的练习用,能够本身建表及定义表中的信息。

3.2 Kotlin将来学习计划

  文中提到的和项目中用到的知识点,都只是Kotlin语言的冰山一角。还有更有趣、奇妙的的地方值得去发现,相信之后能够在项目中将之前习觉得常的、繁琐的代码进行更简洁、高效的实现。

相关文章
相关标签/搜索