下面的代码有几个可能的故障。例如,width
可以为 null,或者 r
可以为 false。在所有情况下,我都应该返回一个 result.error()
或类似的东西。
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else if (call.method=="registerTexture") {
val entry: TextureRegistry.SurfaceTextureEntry = texture_registry.createSurfaceTexture();
val surfaceTexture = entry.surfaceTexture();
//TODO: return non-sucess when no width and height passed
val width: Int = call.argument("width")!!
val height: Int = call.argument("height")!!
surfaceTexture.setDefaultBufferSize(width, height)
val response = HashMap<String, Long>()
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
val r = RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)
if (!r) {
Log.d(LOG_TAG, "attention: failed result from registerSurfaceTextureNativeHandler")
}
response.put("textureId", entry.id())
result.success(response)
}
}
在 Rust 上,我会将所有这些变成一个导致 Result<(), Error>
的闭包,然后在 onMethodCall
内执行闭包,如果出现错误,我会返回一个错误。此外,闭包将充满以 ?
结尾的调用,因此它会自动返回具有转换为 Error
的 From<>
实现的错误。
如何在 Kotlin 中有效地做到这一点?有没有办法在这个闭包中创建一个闭包并轻松返回成功或错误,然后根据这个结果我调用 result.sucess
或 result.error
?
回答1
有一个 runCatching
函数可以调用任何东西。在以下 lambda 闭包中,您调用它的对象是“this
”。你可以为成功返回一些东西,也可以为失败抛出一些东西。然后您可以将此结果解压缩到您的 Result
对象中。 error()
、require()
和 check()
是在不中断代码流的情况下在特定条件下抛出的有用方法。
要从 lambda 封装返回某些内容,您可以使用 return@nameOfFunctionLambdaIsPassedTo
手动执行此操作,或者让 lambda 的最后一个表达式为 return value。 when
表达式可以用作 lambda 的最后一个(唯一)表达式,因此 when
的每个分支中的最后一件事是成功返回的结果(或抛出的错误)。
这是一个例子:
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
call.runCatching {
when(method) {
"getPlatformVersion" -> "Android ${android.os.Build.VERSION.RELEASE}"
"registerTexture" -> {
val entry = texture_registry.createSurfaceTexture()
val surfaceTexture = entry.surfaceTexture()
val width: Int = argument("width") ?: error("no width passed")
val height: Int = argument("height") ?: error("no height passed")
surfaceTexture.setDefaultBufferSize(width, height)
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
check(RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)) {
"attention: failed result from registerSurfaceTextureNativeHandler"
}
mapOf("textureId", entry.id())
}
else -> error("unsupported method name: $method")
}
}
.onSuccess(result::success)
.onFailure(result::failure)
}
如果你想避免调用 onSuccess
/onFailure
,你可以创建一个通用的扩展函数,你可以像这样重复使用:
inline fun MethodCall.runForResult(result: Result, block: MethodCall.() -> Any) {
runCatching(block).onSuccess(result::success).onFailure(result::failure)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
call.runForResult(result) {
when(method) {
"getPlatformVersion" -> "Android ${android.os.Build.VERSION.RELEASE}"
"registerTexture" -> {
val entry = texture_registry.createSurfaceTexture()
val surfaceTexture = entry.surfaceTexture()
val width: Int = argument("width") ?: error("no width passed")
val height: Int = argument("height") ?: error("no height passed")
surfaceTexture.setDefaultBufferSize(width, height)
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
check(RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)) {
"attention: failed result from registerSurfaceTextureNativeHandler"
}
mapOf("textureId", entry.id())
}
else -> error("unsupported method name: $method")
}
}
}
回答2
我希望这可以帮助你。
注意:我假设 result.success()
接受 Any
因为你返回 String
或 HashMap
作为参数,但 kotlin.Result
没有几个通用的成功参数。您可以使用 kotlin.Pair<A, B>
作为 kotlin.Result
的成功类型:D
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
val finalResult: kotlin.Result<Any> = call.run {
if (method == "getPlatformVersion") kotlin.Result.success("Android ${android.os.Build.VERSION.RELEASE}")
else if (method == "registerTexture") {
val entry: TextureRegistry.SurfaceTextureEntry = texture_registry.createSurfaceTexture();
val surfaceTexture = entry.surfaceTexture();
val width = argument("width") ?: return@run kotin.Result.failure(IllegalArgumentException("width is null"))
val height = argument("height") ?: return@run kotlin.Result.failure(IllegalArgumentException("height is null"))
surfaceTexture.setDefaultBufferSize(width, height)
val response = HashMap<String, Long>()
RendererPlugin.surfaceTextureMap.put(entry, surfaceTexture)
val r = RendererPlugin.registerSurfaceTextureNativeHandler(entry.id(), surfaceTexture)
if (!r) return@run kotlin.Result.failure(IllegalArgumentException("r is false"))
response.put("textureId", entry.id())
kotlin.Result.success(response)
}
else kotlin.Result.failure(IllegalStateException("undefined call.method"))
}
with (finalResult) {
onSuccess(result::success)
onFailure(result::fail)
}
}