gpt4 book ai didi

java - Retrofit 2 的自定义 CallAdapter 和 Android 上的线程问题

转载 作者:行者123 更新时间:2023-11-29 08:36:11 25 4
gpt4 key购买 nike

在 Retrofit2 中,当我使用 Retrofit 在 samples/ErrorHandlingAdapter.java 上提供的自定义 CallAdapter 进行错误处理时,回调方法在后台线程而不是主线程上执行,不像默认的 CallAdapter (Call),它在主线程上执行。我通过在两者上运行 Thread.currentThread().getName() 来确保这一点

这对我来说是个大问题。我不想每次想在 ui-thread 中做某事时都使用 runOnUiThread 方法。

上面提到的ErrorHandlingAdapter源码:

/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.retrofit;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.Executor;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Callback;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.http.GET;

/**
* A sample showing a custom {@link CallAdapter} which adapts the built-in {@link Call} to a custom
* version whose callback has more granular methods.
*/
public final class ErrorHandlingAdapter {
/** A callback which offers granular callbacks for various conditions. */
interface MyCallback<T> {
/** Called for [200, 300) responses. */
void success(Response<T> response);
/** Called for 401 responses. */
void unauthenticated(Response<?> response);
/** Called for [400, 500) responses, except 401. */
void clientError(Response<?> response);
/** Called for [500, 600) response. */
void serverError(Response<?> response);
/** Called for network errors while making the call. */
void networkError(IOException e);
/** Called for unexpected errors while making the call. */
void unexpectedError(Throwable t);
}

interface MyCall<T> {
void cancel();
void enqueue(MyCallback<T> callback);
MyCall<T> clone();

// Left as an exercise for the reader...
// TODO MyResponse<T> execute() throws MyHttpException;
}

public static class ErrorHandlingCallAdapterFactory extends CallAdapter.Factory {
@Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit) {
if (getRawType(returnType) != MyCall.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalStateException(
"MyCall must have generic type (e.g., MyCall<ResponseBody>)");
}
Type responseType = getParameterUpperBound(0, (ParameterizedType) returnType);
Executor callbackExecutor = retrofit.callbackExecutor();
return new ErrorHandlingCallAdapter<>(responseType, callbackExecutor);
}

private static final class ErrorHandlingCallAdapter<R> implements CallAdapter<R, MyCall<R>> {
private final Type responseType;
private final Executor callbackExecutor;

ErrorHandlingCallAdapter(Type responseType, Executor callbackExecutor) {
this.responseType = responseType;
this.callbackExecutor = callbackExecutor;
}

@Override public Type responseType() {
return responseType;
}

@Override public MyCall<R> adapt(Call<R> call) {
return new MyCallAdapter<>(call, callbackExecutor);
}
}
}

/** Adapts a {@link Call} to {@link MyCall}. */
static class MyCallAdapter<T> implements MyCall<T> {
private final Call<T> call;
private final Executor callbackExecutor;

MyCallAdapter(Call<T> call, Executor callbackExecutor) {
this.call = call;
this.callbackExecutor = callbackExecutor;
}

@Override public void cancel() {
call.cancel();
}

@Override public void enqueue(final MyCallback<T> callback) {
call.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, Response<T> response) {
// TODO if 'callbackExecutor' is not null, the 'callback' methods should be executed
// on that executor by submitting a Runnable. This is left as an exercise for the reader.

int code = response.code();
if (code >= 200 && code < 300) {
callback.success(response);
} else if (code == 401) {
callback.unauthenticated(response);
} else if (code >= 400 && code < 500) {
callback.clientError(response);
} else if (code >= 500 && code < 600) {
callback.serverError(response);
} else {
callback.unexpectedError(new RuntimeException("Unexpected response " + response));
}
}

@Override public void onFailure(Call<T> call, Throwable t) {
// TODO if 'callbackExecutor' is not null, the 'callback' methods should be executed
// on that executor by submitting a Runnable. This is left as an exercise for the reader.

if (t instanceof IOException) {
callback.networkError((IOException) t);
} else {
callback.unexpectedError(t);
}
}
});
}

@Override public MyCall<T> clone() {
return new MyCallAdapter<>(call.clone(), callbackExecutor);
}
}
}

在 Android 中,我在进行任何调用之前将 ErrorHandlingAdapter 添加到 Retrofit:

// Initializing retrofit
BooleanTypeAdapter typeAdapter = new BooleanTypeAdapter();
gson = new GsonBuilder().setLenient().registerTypeAdapter(boolean.class, typeAdapter).create();
apiService = new Retrofit.Builder().baseUrl(BASE_API_URL)
.addCallAdapterFactory(new ErrorHandlingCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(ApiService.class);

最佳答案

要在主线程上获得回调,您应该使用 MyCallAdapter 中提供的 callbackExecutor

callbackExecutor.execute(new Runnable() {
@Override
public void run() {

int code = response.code();
if (code >= 200 && code < 300) {
callback.success(response);
} else if (code == 401) {
callback.unauthenticated(response);
} else if (code >= 400 && code < 500) {
callback.clientError(response);
} else if (code >= 500 && code < 600) {
callback.serverError(response);
} else {
callback.unexpectedError(new RuntimeException("Unexpected response " + response));
}
}
});

样本有一个 TODO 写成:

// TODO if 'callbackExecutor' is not null, the 'callback' methods should be executed // on that executor by submitting a Runnable. This is left as an exercise for the reader.

它是一个运行在android UI线程上的Retrofit回调执行器。

See here & here

关于java - Retrofit 2 的自定义 CallAdapter 和 Android 上的线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43961970/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com