Retrofit将标记添加到原始请求对象

Rah*_*sia 8 android retrofit2 okhttp3

我正在尝试解决一个问题,我将进行几个异步调用,并根据原始请求,我正在执行一项任务.为了解决这个问题,我正在尝试为每个请求添加一个TAG,然后成功响应,我可以获取标记并根据标记采取行动.在这里,我只使用TAG来识别原始请求.

问题

在调用enqueue方法之前,我将标记设置为原始请求.但是当我在成功的回调中得到响应时,我得到的是我没有设置的不同标签.不知何故,请求对象本身就是那里的标记对象.我不确定,怎么样?

请检查以下代码 -

GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
                final Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit");

                // Set the string tag to the original request object.
                call.request().newBuilder().tag("hello").build();


                call.enqueue(new Callback<List<Contributor>>() {
                    @Override
                    public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
                        Log.d("tag", response.raw().request().tag().toString());
                        // I'm getting Request{method=GET, url=https://api.github.com/repos/square/retrofit/contributors, tag=null} as the value of the tag. WHY????
                        final TextView textView = (TextView) findViewById(R.id.textView);
                        textView.setText(response.body().toString());
                    }
                    @Override
                    public void onFailure(Call<List<Contributor>> call, Throwable t) {
                        final TextView textView = (TextView) findViewById(R.id.textView);
                        textView.setText("Something went wrong: " + t.getMessage());
                    }
                });
Run Code Online (Sandbox Code Playgroud)

有人可以指出我在这里做错了什么.任何帮助,将不胜感激.

max*_*ime 5

该解决方案显然是一种hack,但它可以工作。

假设您像这样创建Retrofit服务:

 public <S> S createService(Class<S> serviceClass) {

    // Could be a simple "new"
    Retrofit.Builder retrofitBuilder = getRetrofitBuilder(baseUrl); 

    // Could be a simple "new"
    OkHttpClient.Builder httpClientBuilder = getOkHttpClientBuilder();  

    // Build your OkHttp client
    OkHttpClient httpClient = httpClientBuilder.build();

    Retrofit retrofit = retrofitBuilder.client(httpClient).build();

    return retrofit.create(serviceClass);
}
Run Code Online (Sandbox Code Playgroud)

您将需要向CallFactoryRetrofit实例添加一个新实例,因此它每次都会添加一个标签。由于标记是只读的,因此我们将使用仅包含一个元素的Object数组,稍后您将可以对其进行更改。

Retrofit retrofit = retrofitBuilder.client(httpClient).callFactory(new Call.Factory() {
        @Override
        public Call newCall(Request request) {

            request = request.newBuilder().tag(new Object[]{null}).build();

            Call call = httpClient.newCall(request);

            // We set the element to the call, to (at least) keep some consistency
            // If you want to only have Strings, create a String array and put the default value to null;
            ((Object[])request.tag())[0] = call;

            return call;
        }
    }).build();
Run Code Online (Sandbox Code Playgroud)

现在,在创建呼叫之后,您将能够更改标签的内容:

((Object[])call.request().tag())[0] = "hello";
Run Code Online (Sandbox Code Playgroud)


Vla*_*lad 5

对我来说,这段代码正在工作

val CLIENT: OkHttpClient = OkHttpClient.Builder().apply {
    addInterceptor(TagInterceptor())
}.build()

val SERVER_API: ServerApi = Retrofit.Builder()
    .client(CLIENT)
    .baseUrl(BASE_URL)
    .build()
    .create(ServerApi::class.java)

interface ServerApi {

    @GET("api/notifications")
    @Tag("notifications")
    suspend fun getNotifications(): ResponseBody
}

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
annotation class Tag(val value: String)

internal class TagInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val builder = request.newBuilder()
        request.tag(Invocation::class.java)?.let {
            it.method().getAnnotation(Tag::class.java)?.let { tag ->
                builder.tag(tag.value)
            }
        }
        return chain.proceed(builder.build())
    }
}
Run Code Online (Sandbox Code Playgroud)

然后按标签取消

fun OkHttpClient.cancelAll(tag: String) {
    for (call in dispatcher().queuedCalls()) {
        if (tag == call.request().tag()) {
            call.cancel()
        }
    }
    for (call in dispatcher().runningCalls()) {
        if (tag == call.request().tag()) {
            call.cancel()
        }
    }
}

CLIENT.cancelAll("notifications")
Run Code Online (Sandbox Code Playgroud)