在 Kotlin 里用 Promise
刚刚看 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") }
嗯,以及我现在越来越觉得我一个月前辞职实在是绝赞的决定。