Kotlin Android GRPC异步任务:动态传递不同网络调用函数
解决方案:用Kotlin泛型+高阶函数实现通用GRPC任务
当然可以!Kotlin的泛型和高阶函数正好能解决你这个问题——不用为每个GRPC调用写单独的AsyncTask子类,我们可以把具体的GRPC调用逻辑作为参数传递,同时适配不同的返回类型。
核心思路
- 定义一个通用的
AsyncTask子类,用泛型<T>表示GRPC调用的返回类型 - 把具体的GRPC调用逻辑(比如
stub.sayHello(request))封装成一个高阶函数,作为参数传给这个通用任务 - 在通用任务的
doInBackground里,统一处理Channel创建、Stub初始化,然后执行传入的GRPC逻辑
通用GRPC任务实现
class GenericGrpcTask<T>( private val host: String, private val port: Int, private val grpcCall: (emeraldSRVGrpc.emeraldSRVBlockingStub) -> T ) : AsyncTask<Void, Void, Result<T>>() { private var channel: ManagedChannel? = null override fun doInBackground(vararg params: Void?): Result<T> { return try { // 统一创建Channel和Stub channel = ManagedChannelBuilder.forAddress(host, port) .usePlaintext() .build() val stub = emeraldSRVGrpc.newBlockingStub(channel) // 执行传入的具体GRPC调用逻辑 val result = grpcCall(stub) Result.success(result) } catch (e: Exception) { val sw = StringWriter() val pw = PrintWriter(sw) e.printStackTrace(pw) pw.flush() Result.failure(Exception("Failed... : ${sw.toString()}")) } finally { // 关闭Channel channel?.shutdown() } } override fun onPostExecute(result: Result<T>) { super.onPostExecute(result) // 这里可以统一处理结果回调,或者让调用方传入回调 // 如果你需要回调,也可以把回调作为参数传入GenericGrpcTask } }
如何使用这个通用任务
针对不同的GRPC调用,你只需要传入对应的逻辑lambda即可,完全不用写新的Task类:
示例1: 原来的sayHello调用
// 调用sayHello GenericGrpcTask<String>("127.0.0.1", 50002) { stub -> val request = HelloRequest.newBuilder().setName("World").build() val reply = stub.sayHello(request) reply.message // 返回String类型,对应泛型<T>为String }.execute()
示例2: 登录调用(假设LoginRequest和LoginReply是你的GRPC定义)
// 调用login GenericGrpcTask<LoginReply>("127.0.0.1", 50002) { stub -> val request = LoginRequest.newBuilder() .setUsername("user") .setPassword("pass") .build() stub.login(request) // 返回LoginReply类型,泛型<T>自动推导为LoginReply }.execute()
示例3: 登出调用(无返回值或返回Void类型)
// 调用logout,假设返回Void类型 GenericGrpcTask<Void>("127.0.0.1", 50002) { stub -> val request = LogoutRequest.newBuilder().setUserId(123).build() stub.logout(request) }.execute()
额外优化:添加结果回调
如果需要在任务完成后处理结果,可以给GenericGrpcTask添加回调参数:
class GenericGrpcTask<T>( private val host: String, private val port: Int, private val grpcCall: (emeraldSRVGrpc.emeraldSRVBlockingStub) -> T, private val onResult: (Result<T>) -> Unit // 结果回调 ) : AsyncTask<Void, Void, Result<T>>() { // ... 前面的doInBackground逻辑不变 ... override fun onPostExecute(result: Result<T>) { super.onPostExecute(result) onResult(result) // 触发回调 } } // 使用时传入回调 GenericGrpcTask<String>("127.0.0.1", 50002, grpcCall = { stub -> val request = HelloRequest.newBuilder().setName("World").build() stub.sayHello(request).message }, onResult = { result -> if (result.isSuccessful) { // 处理成功结果 val message = result.getOrNull() } else { // 处理错误 val error = result.exceptionOrNull() } } ).execute()
为什么这能解决问题
- 泛型
:适配不同GRPC调用的返回类型,不管是String、自定义Reply对象都能处理 - 高阶函数
grpcCall:把具体的GRPC调用逻辑抽离出来,作为参数传递,实现了逻辑的动态替换 - 复用通用Task:所有GRPC调用都用同一个
GenericGrpcTask,避免了重复创建多个Task类或写重复的doInBackground逻辑
内容的提问来源于stack exchange,提问作者mje1
相关产品推荐
相关产品推荐

