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

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

一. 单例



使用 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


总结



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

相关文章
|
3天前
|
编解码 Java Android开发
FFmpeg开发笔记(三十一)使用RTMP Streamer开启APP直播推流
RTMP Streamer是一款开源的安卓直播推流框架,支持RTMP、RTSP和SRT协议,适用于各种直播场景。它支持H264、H265、AV1视频编码和AAC、G711、OPUS音频编码。本文档介绍了如何使用Java版的RTMP Streamer,建议使用小海豚版本的Android Studio (Dolphin)。加载项目时,可添加国内仓库加速依赖下载。RTMP Streamer包含五个模块:app、encoder、rtmp、rtplibrary和rtsp。完成加载后,可以在手机上安装并运行APP,提供多种直播方式。开发者可以从《FFmpeg开发实战:从零基础到短视频上线》获取更多信息。
27 7
FFmpeg开发笔记(三十一)使用RTMP Streamer开启APP直播推流
|
1天前
|
编解码 Android开发 iOS开发
深入探索Android与iOS开发的差异与挑战
【6月更文挑战第24天】在移动应用开发的广阔舞台上,Android和iOS两大操作系统扮演着主角。它们各自拥有独特的开发环境、工具集、用户基础及市场策略。本文将深度剖析这两个平台的开发差异,并探讨开发者面临的挑战,旨在为即将踏入或已在移动开发领域奋斗的开发者提供一份实用指南。
18 13
|
2天前
|
XML Java 开发工具
Android Studio开发Android TV
【6月更文挑战第19天】
|
4天前
|
Java 开发工具 Android开发
安卓与iOS开发差异解析
【6月更文挑战第21天】本文旨在深入探讨安卓和iOS两大移动操作系统在应用开发过程中的主要差异。通过对比分析,揭示各自的设计哲学、编程语言选择、用户界面构建、性能优化策略以及发布流程的异同。文章将提供开发者视角下的实用信息,帮助他们更好地理解各自平台的特点和挑战,从而做出更明智的开发决策。
|
21小时前
|
Java 开发工具 Android开发
探索Android与iOS开发的差异:平台选择对项目成功的影响
在移动应用开发的广阔天地中,Android和iOS两大平台各自占据着半壁江山。本文将深入探讨这两个平台在开发过程中的关键差异点,包括编程语言、开发工具、用户界面设计、性能优化以及市场覆盖等方面。通过对这些关键因素的比较分析,旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和目标受众做出明智的平台选择。
|
3天前
|
Java Android开发 Kotlin
Android面试题:App性能优化之Java和Kotlin常见的数据结构
Java数据结构摘要:ArrayList基于数组,适合查找和修改;LinkedList适合插入删除;HashMap1.8后用数组+链表/红黑树,初始化时预估容量可避免扩容。SparseArray优化查找,ArrayMap减少冲突。 Kotlin优化摘要:Kotlin的List用`listOf/mutableListOf`,Map用`mapOf/mutableMapOf`,支持操作符重载和扩展函数。序列提供懒加载,解构用于遍历Map,扩展函数默认参数增强灵活性。
13 0
|
4天前
|
Android开发
Android Gradle开发—脚本实现自动打包后复制一份APK文件,并修改APK名称,到指定目录作备份
Android Gradle开发—脚本实现自动打包后复制一份APK文件,并修改APK名称,到指定目录作备份
13 0
|
缓存 开发工具 Android开发
Android App性能评测分析-启动时间篇
1、前言 随着项目版本的迭代,App的性能问题会逐渐暴露出来,而好的用户体验与性能表现紧密相关,性能问题从应用的启动优化开始,下面会根据实际app性能测试案例,进行app性能评测之启动时间的分析和总结。
4179 0
|
Shell Linux 测试技术
Android App性能评测分析-cpu占用篇
1、前言 很多时候在使用APP的时候,手机可能会发热发烫。这是因为CPU使用率过高,CPU过于繁忙,会使整个手机无法响应用户,整体性能降低,用户体验就会很差,也容易引起ANR等等一系列问题。
5001 0
|
Java 测试技术 程序员
Android App性能评测分析-内存篇
1、内存了解 在Android App的性能优化的各个部分里,内存方面的知识较多且不易理解,内存的问题绝对是最令人头疼的一部分,需要对内存基础知识、内存分配、内存管理机制等非常熟悉,才能排查问题。
2118 0