[6] —— 回调函数在 Kotlin 里的奇妙玩法

本文涉及到的知识点有:扩展函数、Lambda 表达式的高级应用

在 Android 6.0 之后系统加强了对敏感权限的管理,一些敏感权限必须要通过动态权限申请来获得,本文的内容就从这里展开;

一个正常的权限申请流程大致是这样的:

  1. 检查是否存在权限
  2. 如果不存在则申请,存在则进入功能
  3. 如果用户拒绝则弹出对话框告知用户权限的用处,并提供跳转到设置页面的功能;

我使用的是网上比较流行的一个权限申请框架 # tbruyelle/RxPermissions ,当然本文的重点并不是如何使用这个库。

如上所述,我们在一个应用中可能会有很多需要申请不同权限的位置,我们应该为每处需要敏感权限的位置做类似的处理。虽然我们使用了 RxPermissions,但是还是需要在用户拒绝的位置写大量重复的弹窗提示代码,这一点也不优雅。

我们都知道在 Kotlin 中函数也是可以作为参数传入的,说道到这里不知道你有没有想起点什么,我们在使用 Java 编写 Android 代码时时常使用的各种 Listener,不就是类似这样的一个情况么?

我们调用 setXXXListener 函数,并且传入一个接口的匿名内部类实现,这样的操作我们称之为回调,我们传入的这个 Listener 被中的方法称为回调函数,在 Kotlin 里我们也可以按照这种方式来书写:

//Java中的匿名内部类,在 Kotlin 中可以使用 object 实现
mBtnCallback.setOnClickListener(object :View.OnClickListener{
    override fun onClick(v: View?) {
        println("onclick")
    }

也许你在书写类似代码时已经发现了一些端倪:


Lambda 表达式

所有的类似接口,在 Kotlin 中都有一些新的签名,这是因为在 Kotlin 里函数也是参数的一种,在 Java 中只包含一个方法的接口,在 Kotlin 中都可以使用 Lambda 表达式来达成一样的效果。

这样做最大的好处就是简化代码,当我们在阅读代码时更加简洁易读,比如上述代码完全可以简化成:

 mBtnCallback.setOnClickListener { println("onclick") }

非但如此,以前我们在写一些耗时操作时,通常需要申明一些接口作为回调函数使用,在调用时再用匿名内部类来操作得到的结果,现在你可以这样书写了:

fun doSomeThingNeedTime(call: (response:String) -> Unit) {
    Thread.sleep(4000)
    var response = "xxxx"  //我们假装这里进行了网络请求
    call(response)
}

doSomeThingNeedTime { response->
            println(response)
        }

实际应用

在我们实际应用时其实十分简单,下面的代码也许可以帮你加深对其了解:

//传入权限与权限描述,在需要权限的功能打开之前调用
fun Activity.rxRequestPermissions(vararg permissions: String, describe: String, onGranted:()->Unit) {
    val keylistener = DialogInterface.OnKeyListener { _, keyCode, event ->
        keyCode == KeyEvent.KEYCODE_BACK && event.repeatCount == 0
    }
    var dialog = AlertDialog.Builder(this)
            .setTitle("权限申请")
            .setMessage("${describe}为必选项,开通后方可正常使用APP,请在设置中开启。")
            .setOnKeyListener(keylistener)
            .setCancelable(false)
            .setPositiveButton("去开启") { _, _ ->
//                JumpPermissionManagement.GoToSetting(this)
                finish()
            }
            .setNegativeButton("结束") { _, _ ->
                Toast.makeText(this, "${describe}权限未开启,不能使用该功能!", Toast.LENGTH_SHORT).show()
                finish()
            }
            .create()
    val rxPermissions = RxPermissions(this)
    //传递kotlin的可变长参数给Java的可变参数的时候需要使用修饰符 * ;这个修饰符叫做Speread Operator
    // 它只支持展开的Array 数组,不支持List集合,它只用于变长参数列表的实参,不能重载,它也不是运算符;
    rxPermissions.request(*permissions)
            .subscribe {granted ->
                if (granted) {
                    onGranted()
                } else {
                    dialog.show()
                }
            }
}

上述代码就是我写的 Activity 的一个扩展函数,用于实现我们前文提到的更方便的动态申请权限,请看我们的函数申明:

fun Activity.rxRequestPermissions(vararg permissions: String, describe: String, onGranted:()->Unit) {
 }

我们传入的前三个参数是分别是:要申请的权限(对于我们的扩展函数而言是一个可变长参数),第二个参数我们使用“key = value” 这种形式传递,第三个参数就一个回调函数onGranted:()->Unit

其中 onGranted,是我们自己命名的函数名,冒号后面是我们的函数描述即:没有传入参数,返回值类型为 Unit。在我们的扩展函数体中直接将他作为一个函数调用即可,需要注意的是必须要填写括号,AS的自动补全并不会补全这个括号,没有括号时编译器也不会报错。

如何使用
在打开需要申请权限的功能位置,我们只要写下以下的数行代码即可:

mBtnRecord.setOnClickListener {
    rxRequestPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO, describe = "相机、存储、录音") {
        startActivityForResult(Intent(this@MainActivity, VideoRecordActivity::class.java), REQUEST_VIDEO)
    }
}

首先传入需要申请的权限、权限描述(key = value),第三个参数为一个Lambda表达式,这里进行的是存在权限时需要执行的操作。Lambda 表达式作为函数的最后的一个参数时,我们可以把它放在圆括号外书写。

最终使用时的效果如下:


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

推荐阅读更多精彩内容