背景:所以,我有一个很大的项目,它有很多API函数。我正在考虑完全迁移到协同机制,但是由于它们是作为Callback而不是Deferred实现的,所以我无法有效地使用它们。例如:我想做apiCallOne()、apiCallTwo()和apiCallThree()异步,并调用.await()等待最后一个请求完成后再更改UI。
现在,该项目的结构如下:
在最底部(或顶部)是ApiService.java
interface ApiService {
@GET("...")
Call<Object> getData();
...
}然后我有了一个ClientBase.java:函数createRequest()是解析更新响应的主要函数。
void getUserName(String name, ApiCallback<ApiResponse<...>> callback) {
createRequest(ApiService.getData(...), new ApiCallback<ApiResponse<?>>() {
@Override
public void onResult(ServiceResponse response) {
callback.onResult(response);
}
});
}
private void createRequest(Call call, final ApiCallback<ApiResponse<?>> callback) {
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, retrofit2.Response response) {
//heavy parsing
}
// return request results wrapped into ApiResponse object
callback.onResult(new ApiResponse<>(...));
}
@Override
public void onFailure(Call call, Throwable t) {
// return request results wrapped into ApiResponse object
callback.onResult(...);
}
});
}ApiCallback和ApiResponse看起来如下:
public interface ApiCallback<T> {
void onResult(T response);
}
public class ApiResponse<T> {
private T mResult;
private ServiceError mError;
...
}因此,在这之前,我还使用了ApiClient.java,它使用ClientBase.createRequest()
public void getUserName(String name, ApiCallback<ApiResponse<..>> callback) {
ClientBase.getUserName(secret, username, new ServiceCallback<ServiceResponse<RegistrationInvite>>() {
@Override
public void onResult(ServiceResponse<RegistrationInvite> response) {
...
callback.onResult(response);
}
});
}如你所见,这是非常非常糟糕的。我如何传输一些代码--至少要确保ApiClient.java函数返回Deferred对象?(我愿意为此创建另一个包装类)
发布于 2019-04-11 13:23:26
因此,通常,一种简单的方法是从挂起函数返回一个suspendCancellableCoroutine,然后您可以异步完成该函数。因此,在你的例子中,你可能会写一些这样的东西:
suspend fun getUserName(name: String): ApiResponse<...> {
return suspendCancellableCoroutine { continuation ->
createRequest(ApiService.getData(...), new ApiCallback<ApiResponse<...>>() {
@Override
public void onResult(ApiResponse<...> response) {
continuation.resume(response)
}
});
}
}基本上,您返回等效的SettableFuture,然后在成功或失败时标记它完成。如果您想通过异常处理来处理错误,也可以使用continueWithException(Throwable)。
说:
由于您使用的是Retrofit,我建议您只添加加强型2-科特林-协同线.适配器依赖项,这将为您提供本机支持。
发布于 2019-04-13 14:55:30
ApiService.java转换为ApiService.kt:
接口ApiService { @GET("…")fun (…)*调用)}
若要将服务方法的返回类型从Call更改为Deferred,可以将上面的行修改为:
fun (…)*推迟)onCreate() In override fun onCreate(savedInstanceState: Bundle?){ in MainActivity.kt中:
.addCallAdapterFactory(CoroutineCallAdapterFactory()) .baseUrl(“YOUR_URL”) .build() .build() val service = retrofit.create(ApiService::class.java) //以上:在Kotlin中创建类引用/成员引用val apiOneTextView = findViewById(R.id.api_one_text_view) //将类型参数转换为findViewByIdPrecomputedTextCompat.getTextFuture的方法,根据Android,它是PrecomputedText的助手,它返回与AppCompatTextView.setTextFuture(Future)一起使用的未来。MainActivity.kt中:
//设置一个Coroutine作用域GlobalScope.launch(Dispatchers.Main){ val = measureTimeMillis{ //重要,以始终检查您是否在正确的轨道上尝试{ initialiseApiTwo() initialiseApiThree() val createRequest = service.getData(your_params_here) apiOneTextView.text=“您在这里使用api详细信息使用${createRequest.await().your_params_here}”} catch (例外: IOException) {apiOneTextView.text=“您的网络不可用.“}println(”$time“) //登录到控制台,执行}所需的总时间(毫秒)。
延迟+等待=挂起等待结果,不阻塞主UI线程initializeApiTwo()和initializeApiThree(),您可以使用类似的GlobalScope.launch(Dispatchers.Main){.& val createRequestTwo = initializeApiTwo() (其中:private suspend fun initializeApiTwo() = withContext(Dispatchers.Default) { // coroutine作用域)对它们使用private suspend fun &遵循讨论点2中概述的相同方法。在您的MainActivity.kt中:
//设置一个协同作用域GlobalScope.launch(Dispatchers.Main){ val = measureTimeMillis{ //重要,以始终检查您是否在正确的轨道上尝试{
val apiTwoAsync =异步{ initialiseApiTwo() }
val apiThreeAsync =异步{ initialiseApiThree() }
val createRequest =异步{ service.getData(your_params_here) }
val dataResponse = createRequest.await()
ApiOneTextView.text=“使用${dataResponse.await().your_params_here}实现api详细信息”
} catch (例外: IOException) {apiOneTextView.text=“您的网络不可用。”}println(“$time”) //登录到控制台,总时间以毫秒为单位执行}
要在本节中了解更多关于组合挂起函数的信息,您可以访问本节关于并发的使用Kotlin文档这里提供的异步。
PrecomputedTextCompat.getTextFuture的方法:
如果(真){ (apiOneTextView as AppCompatTextView).setTextFuture( PrecomputedTextCompat.getTextFuture( apiOneTextView.text,apiOneTextView.text null) )}希望这会有帮助。
https://stackoverflow.com/questions/55626871
复制相似问题