在 Java 开发中的单例模式一般都是私有化构造并且使用静态字段持有这个类仅有的实例。但是在 Kotlin 中并没有 static 关键字,那么单例模式该如何实现呢?
Kotlin 通过使用 “对象声明”功能为这一切提供了最高级的语言支持。
什么是对象声明呢?对象声明将类的声明与该类的单一实例声明结合到一起,也就是说,你可以像声明一个类一样声明一个对象,这个对象在定义的时候就创造了,不需要在任何地方调用构造方法初始化,因此,对象声明没有构造方法,并且是唯一实例。
object User{ // 使用 object 关键字声明对象,高效的定义了 User 类和他的一个变量
val str = ""
fun printStr(){}
}
// 可以直接通过对象名.属性名/方法名 调用
User.str
User.printStr()
Kotlin 中一个关键字实现单例模式。
单例模式说完了,虽说 Kotlin 对于 Java 开发者来说入手很简单,但是我相信还是有很多朋友对其语法是不了解的,那么在对工具类封装前,我就来和大家简单聊聊 Kotlin 的语法规则吧。
class Test { // 声明类 Test,默认public final
var str1: String? = null // 声明一个可为空、初始值为 null 的 String 类型属性
var str2: String = null!! // 声明一个没有空安全、初始值为 null 的 String 类型属性
lateinit var str3: String // 声明一个延迟初始化、不能为空的 String 类型属性
var str4: String = "str" // 声明一个不能为空、初始值为 null 的 String 类型属性
var str5 = "str" // 声明一个不能为空、初始值为 “str” 的 String 类型属性
val int1: Int = 1 // 声明一个不能为空、初始值为 1 的 Int 类型属性
fun main1(str: String) : Unit {} // 声明一个参数为 String 类型、无返回值的方法
fun main2(str: String) {} // 声明一个参数为 String 类型、无返回值的方法
fun main3(str: String) : String { // 声明一个参数为 String 类型、返回类型为 String
return str
}
}
Kotlin 中同样使用关键字 class 声明类,但是变量及方法的声明大有不同。
使用关键字 var 声明可变变量,相当于 Java 中的普通变量,使用关键字 val 声明不可变变量,相当于 Java 中 final 修饰的常量。声明变量时,关键字后紧接着的是变量名,冒号后面是变量类型。
使用关键字 fun 声明方法(据说取自于 Kotlin 编程有很多乐趣!),括号内参数声明和变量一致,变量名在前,类型在后。在方法声明的最后加上冒号后面才是返回类型,无返回值时为 Unit 类型,可省略。
Kotlin 是空安全的语言。
什么是空安全?从上面的变量声明中可以看出来,Kotlin 中的类型默认情况下是不允许为空的
var str: String = null // 错误的声明
如果你这样声明一个变量,编译器就会告诉你 str 是不为空的类型,不能赋值为 null,所以,你需要在类型后面加上 ? 来标识这个变量可以为空才能赋值为 null。
var str: String? = null // 正确的声明
而 Kotlin 中的 !! 则被称为非空断言,可以放在任何变量后,将其转换成非空类型,即你告诉编译器这个 变量觉不可能为空,如果为空了,你也做好了抛出异常的准备。非空断言修饰的变量为 null 时,会抛出空指针异常。
安全调用运算符: ?.
var str: String?
str?.toString() -----> if(null != str) str.toString()
Elvis 运算符: ?:
var str: String
str?: "" -----> if(null == str) return "" else return str
简单的基础语法介绍完了,接下来就是工具类的封装了。在笔者之前的一篇文章中已经说过,Android 中弹 Toast 需要的 Context 对象可以是任意对象,那么我们可以使用在整个应用生命周期都存在的 Application 对象。笔者的这个工具类只是简单的封装了弹 Toast 的功能,有需要可以自己拓展。
ToastUtil.kt
object ToastUtil { // 对象声明
/** Context 对象,建议使用 Application */
private lateinit var mContext: Context
/**
* 绑定 Context 对象
*/
fun bindContext(context: Context) {
mContext = context
}
/**
* 弹 Toast,字符串类型
*/
fun show(str: String) {
Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show()
}
/**
* 弹 Toast,字符串资源id
*/
fun show(@StringRes strResID: Int) {
show(mContext.getString(strResID))
}
}
// 绑定Context
ToastUtil.bindContext(app)
// 使用
ToastUtil.show("toast")
ToastUtil.show(R.string.toast)
这样用起来是不是简单方便。
使用 AppManager 一方面能够方便的管理 Activity 以及应用的退出等操作,同时,能在其他有需要的地方很便捷的获取 Activity 对象。
AppManager.kt
object AppManager {
/** 保存 Activity 对象的堆栈 */
private val activityStack: Stack = Stack()
/**
* 添加 Activity 到堆栈
*
* @param activity Activity 对象
*/
fun addActivity(activity: AppCompatActivity) {
activityStack.add(activity)
Log.d("AppManager---->>", "add---->>$activity size---->>${activityStack.size}")
}
/**
* 将 Activity 从堆栈移除
*
* @param activity Activity 对象
*/
fun removeActivity(activity: AppCompatActivity) {
if (activityStack.contains(activity)) {
activityStack.remove(activity)
Log.d("AppManager---->>", "remove---->>$activity size---->>${activityStack.size}")
}
}
/**
* 结束指定 Activity
*
* @param activity Activity 对象
*/
fun finishActivity(activity: AppCompatActivity) {
if (activityStack.contains(activity)) {
activity.finish()
}
}
/**
* 结束指定 Activity
*
* @param cls Activity 类对象
*/
fun finishActivity(clazz: Class) {
val del: AppCompatActivity? = activityStack.lastOrNull { it.javaClass == clazz }
del?.finish()
}
/**
* 获取栈顶的 Activity
*
* @return 栈顶的 Activity 对象
*/
fun peekActivity(): AppCompatActivity {
return activityStack.peek()
}
/**
* 根据类,获取 Activity 对象
*
* @param clazz Activity 类
* @param Activity 类型
*
* @return Activity对象
*/
fun getActivity(clazz: Class): A? {
var target: A? = null
activityStack
.filter { it.javaClass == clazz }
.forEach {
@Suppress("UNCHECKED_CAST")
target = it as A
}
return target
}
/**
* 结束所有Activity
*/
private fun finishAllActivity() {
for (activity in activityStack) {
activity.finish()
}
activityStack.clear()
Log.d("AppManager---->>", "Finish All Activity!")
}
/**
* 退出应用程序
*/
@SuppressLint("MissingPermission")
fun appExit() {
try {
finishAllActivity()
val activityMgr = peekActivity().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
activityMgr.killBackgroundProcesses(peekActivity().packageName)
System.exit(0)
} catch (e: Exception) {
Log.d("AppManager---->>", "Application Exit!")
}
}
}
// Activity 中调用
AppManager.add(activity)
AppManager.remove(activity)
好了,今天就和大家讲了 Kotlin 中单例模式以及两个简单工具类的封装,接下来还会向大家讲解一系列的基类封装以及 Kotlin 语法规则,欢迎关注~