从简单的工具类封装了解 Kotlin 语法

image.png

前言


  • 前面一章中,笔者向大家详细讲解了如何让你的开发环境支持 Kotlin 以及如何在项目中配置使用 Kotlin,当然,要想使用 Kotlin 进行开发,这些是远远不够的,所以,今天笔者就通过对 ToastUtil 及 AppManager 两个工具类的封装,带大家一步步了解 Kotlin 语法。
  • KotlinTest Github:

单例模式


  • 在 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
    

ToastUtil


  • 简单的基础语法介绍完了,接下来就是工具类的封装了。在笔者之前的一篇文章中已经说过,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


  • 使用 AppManager 一方面能够方便的管理 Activity 以及应用的退出等操作,同时,能在其他有需要的地方很便捷的获取 Activity 对象。

  • AppManager.kt

    object AppManager {
    
        /** 保存 Activity 对象的堆栈 */
        private val activityStack: Stack<AppCompatActivity> = 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<out AppCompatActivity>) {
            val del: AppCompatActivity? = activityStack.lastOrNull { it.javaClass == clazz }
            del?.finish()
        }
    
        /**
         * 获取栈顶的 Activity
         *
         * @return 栈顶的 Activity 对象
         */
        fun peekActivity(): AppCompatActivity {
            return activityStack.peek()
        }
    
        /**
         * 根据类,获取 Activity 对象
         *
         * @param clazz Activity 类
         * @param <T> Activity 类型
         *
         * @return Activity对象
         */
        fun <A : AppCompatActivity> getActivity(clazz: Class<out AppCompatActivity>): 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 语法规则,欢迎关注~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容