Born again shelter - promise
type: channel
link: https://bash.kmxz.net/tag/promise/
items: 在 Kotlin 里用 Promise

在 Kotlin 里用 Promise
type: item
date: 2017-05-17T19:15:00+00:00
description: 刚刚看 I/O 直播时听到 Kotlin gets officially supported，真的蛮意外的。Kotlin 的 killer-app 大约就是用来写 Android app 的 Anko。从我初次用 Anko 到现在，已经过去快一年了。遗憾的是在之前的公司里，由于各种各样的原因，一直没法在线上产品中使用 Kotlin。直到我上个月换了工作后——刚刚结束的四月里，使用 Anko，在不到一个月里就写完了两个漂亮的 Android App 并上线，生产力和舒适度实在前所未有。当然，由于我很长时间里的主要在写 JavaScript，于是确实习惯了使用 Promise。我于是就简短地用 Kotlin 写了一个 Promise 实现—— https://github.com/kmxz/Votive/。API 尽可能地接近 JavaScript 中的 Promise；只是所有 Promise 的名称都改成了 Votive。譬如，将 Android 的运行时权限申请封装为 Promise，只需要这么一点 boilerplating：const val REQUEST_CODE_MIN = 6910 const val REQUEST_CODE_MAX = 7910 open class BaseActivity: AppCompatActivity() { private var lastRequestCode = REQUEST_CODE_MIN private var permissionCallback = mutableMapOf<Int, Pair<(Unit) -> Unit, ((Unit) -> Unit)>>() fun withPermission(permission: String) = Votive<Unit, Unit> { resolve, reject -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { val requestCode = lastRequestCode++ if (lastRequestCode > REQUEST_CODE_MAX) { lastRequestCode = REQUEST_CODE_MIN } permissionCallbacks.put(requestCode, Pair(resolve, reject)) ActivityCompat.requestPermissions(this, arrayOf(permission), requestCode) } else { resolve(Unit) } } else { resolve(Unit) } } final override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { if (requestCode in REQUEST_CODE_MIN..REQUEST_CODE_MAX) { val callback = permissionCallbacks.remove(requestCode) if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) { callback?.first?.invoke(Unit) } else { // already removed anyway callback?.second?.invoke(Unit) } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults) } } } 就可以使用 Promise 风格去申请运行时权限：withPermission(Manifest.permission.ACCESS_FINE_LOCATION) .thenSimple { Log.i(locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)) } .catchSimple { alert("Don't give me permission? I'll crash") } 嗯，以及我现在越来越觉得我一个月前辞…