继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

使用Kotlin高效地开发Android App(五)完结篇

fengzhizi715
关注TA
已关注
手记 72
粉丝 1.7万
获赞 594
一. 单例

使用 Java 来编写单例模式的话,可以写出好几种。同样,使用 Kotlin 也可以写出多种单例模式。在这里介绍的是一种使用委托属性的方式来实现单例的写法。

首先,Kotlin 在语法层面上支持委托模式。

委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承。

对于一些很常见的属性,虽然我们可以在每次需要它们的时候手动地实现它们,但更好的方法是一次性全部实现,然后放进一个库里面。换句话说,对其属性值的操作不再依赖于其自身的getter()/setter()方法,而是将其托付给一个代理类,从而每个使用类中的该属性可以通过代理类统一管理。这种方式是委托属性

在Kotlin的标准库中有一系列的标准委托,not null属性是其中之一。它会含有一个可null的变量并会在我们设置这个属性的时候分配一个真实的值。如果这个值在被获取之前没有被分配,它就会抛出一个异常。

当然 by lazy 也可以实现单例,下面我们使用 not null 委托来实现 Application 的单例。

class App : Application() {
    companion object {
        var instance: App by Delegates.notNull()
    }

    override fun onCreate() {
            super.onCreate()
            instance = this
    }
}
二. 封装Extras

使用ExtrasDelegate来封装Extras

import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import kotlin.reflect.KProperty

/**
 *
 * @FileName:
 *          com.safframework.delegate.extras.Extras.kt
 * @author: Tony Shen
 * @date: 2018-06-11 23:56
 * @version V1.0 <描述当前版本功能>
 */
class ExtrasDelegate<out T>(private val extraName: String, private val defaultValue: T) {

    private var extra: T? = null

    operator fun getValue(thisRef: AppCompatActivity, property: KProperty<*>): T {
        extra = getExtra(extra, extraName, thisRef)
        return extra ?: defaultValue
    }

    operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
        extra = getExtra(extra, extraName, thisRef)
        return extra ?: defaultValue
    }

}

fun <T> extraDelegate(extra: String, default: T) = ExtrasDelegate(extra, default)

fun extraDelegate(extra: String) = extraDelegate(extra, null)

@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraName: String, thisRef: AppCompatActivity): T? =
        oldExtra ?: thisRef.intent?.extras?.get(extraName) as T?

@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraName: String, thisRef: Fragment): T? =
        oldExtra ?: thisRef.arguments?.get(extraName) as T?

封装完之后,在MainActivity中传递参数跳转到其他到Activity。

import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.safframework.delegate.R
import com.safframework.delegate.domain.User
import com.safframework.ext.click
import kotlinx.android.synthetic.main.activity_main.*

/**
 *
 * @FileName:
 *          com.safframework.delegate.activity.MainActivity.java
 * @author: Tony Shen
 * @date: 2018-06-13 12:03
 * @version V1.0 <描述当前版本功能>
 */
class MainActivity:AppCompatActivity() {

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initViews()
    }

    private fun initViews() {

        text1.click{

            val intent = Intent(this@MainActivity, Demo4ExtrasDelegateActivity::class.java)
            val u = User("Tony","123456")
            intent.putExtra("user",u)
            intent.putExtra("string","just a test")
            startActivity(intent)
        }

        text2.click {

            val intent = Intent(this@MainActivity, Demo4PrefsDelegateActivity::class.java)
            startActivity(intent)
        }
    }
}

这里的click函数,在使用Kotlin高效地开发Android App(二)中已经讲述过,就不在重复讲述。

Demo4ExtrasDelegateActivity接受从MainActivity中传递过来的参数。

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.safframework.delegate.domain.User
import com.safframework.delegate.extras.extraDelegate
import com.safframework.log.L

/**
 *
 * @FileName:
 *          com.safframework.delegate.activity.Demo4ExtrasDelegateActivity.java
 * @author: Tony Shen
 * @date: 2018-06-13 17:42
 * @version V1.0 <描述当前版本功能>
 */
class Demo4ExtrasDelegateActivity: AppCompatActivity() {

    private val user: User? by extraDelegate("user")
    private val s:String? by extraDelegate("string")

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        L.json(user)
        L.i(s)
    }
}

所传递过来的任何对象类型,都可以使用如下的方式获取Extras。只要保证,extra的key正确即可。

    private val user: User? by extraDelegate("user")
    private val s:String? by extraDelegate("string")

与Extra类似,SharedPreferences也可以使用属性委托的方式进行封装。

三. infix

中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间。中缀表达式允许我们使用一个单词或字母来当运算符用(其本质还是函数调用),忽略调用的点和圆括号。

Kotlin的中缀表达式,需要满足以下条件:

  1. 使用infix修饰
  2. 只有一个参数
  3. 其参数不得接受可变数量的参数且不能有默认值。

例如:

infix fun Int.add(i:Int):Int = this + i

infix fun Int.加(i:Int):Int = this + i

fun main(args: Array<String>) {

    println(5 add 10)
    println(5 加 10)
}

执行结果:

15
15

在 Kotlin 中,使用中缀表达式最经典的例子,莫过于使用kxdate来操作日期。
kxdate github地址:https://github.com/yole/kxdate

val twoMonthsLater = 2.months.fromNow
val yesterday = 1.days.ago

等价于:

val twoMonthsLater = 2 months fromNow
val yesterday = 1 days ago

由此可见,中缀表达式能让代码看起来更加接近于自然语言。

四. inline

Kotlin 天生支持函数式编程,高阶函数和 lambda 是其一大特色。

使用高阶函数会带来一些运行时间效率的损失:每一个函数都是一个对象,并且都会捕获一个闭包。 即那些在函数体内会被访问的变量。 内存分配(对于函数对象和类)和虚拟调用会引入运行时间开销。

使用 inline 修饰的函数,可以从编译器角度将函数的函数体复制到调用处实现内联。

在很多情况下,通过将 Lambda 表达式内联在使用处, 可以消除运行时消耗。

翻看 Kotlin 的 Standard.kt 可以发现它里面的函数 with、apply、run、let 等都使用了 inline。

再举一个例子,对 Closeable 进行扩展,让它支持Java的try-with-resources特性。

inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var closed = false
    try {
        return block(this)
    } catch (e: Exception) {
        closed = true
        try {
            this?.close()
        } catch (closeException: Exception) {
        }
        throw e
    } finally {
        if (!closed) {
            this?.close()
        }
    }
}

该方法已经在 https://github.com/fengzhizi715/SAF-Kotlin-Utils

总结

本文是该系列最后一篇文章,未来不会整理零碎的开发细节,转而会以体系化形式进行整理。

该系列的相关文章:
使用Kotlin高效地开发Android App(四)
使用Kotlin高效地开发Android App(三)
使用Kotlin高效地开发Android App(二)
使用Kotlin高效地开发Android App(一)

打开App,阅读手记
3人推荐
发表评论
随时随地看视频慕课网APP