原标题:一款纯Kotlin编写的开源安卓应用 "Smile"

本文作者

作者:王英豪

链接:

http://blog.csdn.net/yhaolpz/article/details/77922521

本文由作者投稿推送。

1

界面

版块一:段子鸡汤

f0641f6cd6871b0f092d730f98ea70a1.png

版块二:花瓣福利

c7eb257fd6b24a268dbf369c936fe883.png

版块三:动态搞笑图

6854a68cf148850f8825e8bf2c2357e0.gif

9012127925ae482d77dd7c8c548af3a1.gif

2

代码片段

1.数据类

80f50e371267e92bb1c121a6943403b5.png

相关的数据类可以写在同一个文件中,摒弃繁多的 get/set 、toString 等方法,简洁明了!

2.属性委托

6f81a6de0af5d167d3c0f0e77c2c53f6.png

对变量 mDefaultIndex 取值将直接从 SharedPreferences 中取出,对该变量赋值将直接存入 SharedPreferences 中,没有比这更简单的写法了!

2564c16693d22c0bd2ee214f67a49f70.png

什么时候用到 mClient 什么时候初始化它的值,实现延迟初始化如此简单!

3.代码简化神器 anko

8dc0b5b57939c0bc7195a58ca6384c2c.png

一个单词实现线程切换,无需多言,nice !!!

更多内容请前往源码查看 ~

3

如何着手Kotlin

我从对 Kotlin 一窍不通,到完整开发出此 App,共用了 9 天,其中有 4 天只在晚上开发,也就是说共计 5 天 + 4 个晚上。另外由于我对 ui 的挑剔,主题色的挑选及 logo 设计至少占去五分之一的时间。

我并不是在炫耀我的自学能力,Smile 的内容并不算多,肯定有很多大牛比我快,我想表达的是这 9 天的学习及开发过程是刀过竹解、得心应手的。所以我想把这个学习过程分享给大家,只要能帮到一个人,那就是有价值的。

首先,选择一个完整的 kotlin 文档,从第一章开始阅读,尤其是最基础的基本类型、控制流等等,千万不能跳过,边读边把知识点记录下来,期间可以阅读一些博客了解一下别人对这些知识点的理解,但是学习文档是主线,一定不能偏离。

这个过程我持续了三天,主要学习的文档为: Kotlin 语言中文站 ,期间每学到一个知识点我就记录下来,展示一部分:

https://www.kotlincn.net/docs/reference/basic-syntax.html

84cdac977a0d31f1b0f91bd16ae7eba0.png

这样的内容我记录了很多,直接分享出来吧,全文链接:

https://github.com/yhaolpz/Smile/blob/master/kotlinNote.md

这个过程并不需要把所有的知识点都融汇贯通,对于你觉得比较复杂的内容,可以略读,但是不能直接跳过,你至少要知道这个知识点的存在,比如“泛型”章节我第一次阅读的时候真是云里雾里。

OK~ 这个过程完后你一定跃跃欲试了,这个委托功能真的这么酷吗!这个语法竟然这么简洁!如果这样的想法存在的话,那就说明前面的文档学习过程十分成功了!接下来就在 IDE 中尝试吧,仍然有 官方教程为你铺路,除了创建 Kotlin 项目之外,还有 Kotlin 安卓扩展插件、Kotlin 集成第三方框架等教程,这些资料的参考顺序应该处于他人博文之前。

官方教程:https://www.kotlincn.net/docs/tutorials/kotlin-android.html

然后你就可以尽情的投入 Kotlin 的怀抱了,你会遇到代码简化神器 anko,这里推荐一份针对 anko的 kotlin 教程,Smile 中的泛型 preference 委托就参考自这份文档,另外 anko 中的 doAsync 和 uiThread 表示强烈鄙视 Handler 及其他所有切换线程的写法 (⊙_⊙;)

anko:https://github.com/Kotlin/anko/wiki

针对 anko的kotlin教程:https://wangjiegulu.gitbooks.io/kotlin-for-android-developers-zh/kai_shi_shi_yong_anko.html

4

开发心得

开发过程中不要急着集成第三方库

既然你的项目已经选择了 Kotlin,为何不多体验一下它的强大呢?拿请求网络来说,以往的开发习惯可能会促使你尽快把 retrofit 集成进来,暂时搁置它吧,体会一下 kotlin 中请求网络是多么简洁,就算你仍然打算在以后的项目中使用 retrofit,这也没关系,仅这次敲几行代码体会一下也是很美好的。

Ok ~ talk is cheap ,下面看一下 Smile 中是如何请求网络数据的,比如一进去的“搞笑段子”,在其 Fragment 中是这样请求网络数据的:

doAsync {

val data = JokeService.getData(mPage)

uiThread {

mLoading = false

if(data == null) {

showSnackbar(view asViewGroup, "加载失败")

return@uiThread

}

...

doAsync 中会自动切换到子线程,执行完 getData() 方法后,会自动切换到 ui 线程接着执行 uiThread{ } 中的代码,来看看 getData() 方法我是怎么实现的:

fun getData(page: Int, maxResult: Int = 10): List? {

varforecastJsonStr: String? = null

try{

forecastJsonStr =

URL(buildBaseUrl(page, maxResult)).readText()

} catch(e: Exception) {

returnnull

}

val data =

Gson().fromJson(forecastJsonStr, JokeResult::class.java)

val jokes: List = data.showapi_res_body.contentlist

returnif(jokes.isNotEmpty()) jokes elsenull

}

注意,其中请求网络的代码仅仅一行:

forecastJsonStr =

URL(buildBaseUrl(page, maxResult)).readText()

URL 仍然是原来 java.net 包的类,但 readText() 函数正是 kotlin 的杰作, Kotlin 支持扩展函数和扩展属性,readText() 就是 URL 类的扩展函数,除此之外还扩展了 readBytes() 函数,这代表着在 kotlin 中请求网络仅仅需要一行代码,再配合强大的 doAsync 、uiThread 方法,如此简单的实现了网络请求,在写法上是不是比以往的 rxJava+retrofit 更简洁呢?

回到 getData() 方法,看最后的返回语句:

returnif(jokes.isNotEmpty()) jokes elsenull

在 Kotlin 中,if 语句是可以有一个返回值的,但是看起来似乎可以更简单的使用 java 中的三元操作符 ? : 实现,但是三元操作符 ? : 中是不能嵌套其他代码的,下面仍然是 Smile 中的代码:

overridefun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean{

if(keyCode == KeyEvent.KEYCODE_BACK) {

mBackPressedTime = if(mIsMenuOpen) {

drawerLayout.closeDrawers()

mBackPressedTime

} else{

System.currentTimeMillis()

}

}

returntrue

}

其中要实现的功能是:当按下返回键时,首先判断侧滑菜单是否打开,若打开就关闭之并执行 mBackPressedTime = mBackPressedTime 赋值语句;若处于关闭状态就执行 mBackPressedTime = System.currentTimeMillis() 赋值语句,其中使用 if 具有返回值这一特性很方便的实现了这一点。

为什么我要根据侧滑状态的打开状态分别给 mBackPressedTime 赋不同的值呢?

我想实现的功能是:在侧滑菜单关闭的状态下,快速按两次返回键,则退出应用。

通过监听 mBackPressedTime 值的变化可以实现,这里用到了 Kotlin 的属性委托:数据监听委托,来看怎么对 mBackPressedTime 实现数据变化监听的:

varmBackPressedTime byDelegates.observable( 0L) {

_, old, new->

if( new- old > 1000) {

showSnackbar(coordinatorLayout,

getString(R. string.exit_message))

}

if( new- old in1..1000) {

mDefaultIndex = mCurrentIndex

finish()

}

}

在声明变量的时候通过 by 关键字实现属性委托,Delegates.observable(0L) 是 Kotlin 自带的一种数据监听属性委托,代码中规定,当两次按下的时间间隔大于 1秒时显示提示框,小于 1 秒时退出应用。

最后再解释一下这段代码:

if( new- old in1..1000) {

mDefaultIndex = mCurrentIndex

finish()

}

可以看到判断范围的写法与 Java 中不同, 在 Java 中我们是这样写的:

if( new- old >= 1&& new- old<= 1000)

另外就是:

mDefaultIndex= mCurrentIndex

在本文开头贴出的代码片段中有提到过,对 mDefaultIndex 赋值意味着直接将值存入到 preference 文件中了。

这里就不再展示其他代码了,更多内容请前往源码查看 ~

源码:

https://github.com/yhaolpz/Smile

ZZS

死板、呆萌、宅、不解人意…作为一名敲代码为生的程序员,你是不是被旁人贴过太多不属于你的标签?

1024程序员节这天,100offer给你一个撕掉标签的机会:关注100offer微信号,发送一段话/一张图/一段视频/一条语音…展示你除了敲代码以外的神技能,还有最高价值1024元的“程序员兴趣基金”等你拿!返回搜狐,查看更多

责任编辑:

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐