Модернизация Добавление тега к исходному объекту запроса

Я пытаюсь решить проблему, когда я буду делать пару асинхронных вызовов и на основе исходного запроса выполнять задачу. Чтобы решить эту проблему, я пытаюсь добавить TAG к каждому запросу, а затем при успешном ответе я могу получить тег и выполнить действие на основе тега. Здесь я использую TAG только для идентификации исходного запроса.

Проблема

Перед вызовом метода постановки в очередь я устанавливаю тег в исходный запрос. Но когда я получаю ответ в успешном обратном вызове, я получаю другой тег, который я не устанавливал. Каким-то образом сам объект запроса появляется как объект тега. Я не уверен, как???

Пожалуйста, проверьте код ниже-

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());
                    }
                });

Может ли кто-нибудь указать, что именно я делаю неправильно здесь. Любая помощь будет оценена по достоинству.


person Rahul Chaurasia    schedule 06.02.2017    source источник


Ответы (2)


Это решение явно является хаком, но оно работает.

Допустим, вы создаете свой сервис 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);
}

Вам нужно будет добавить новый CallFactory в свой экземпляр Retrofit, чтобы он каждый раз добавлял тег. Поскольку тег будет доступен только для чтения, мы будем использовать массив 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();

Теперь, после создания звонка, вы сможете изменить содержимое своего тега:

((Object[])call.request().tag())[0] = "hello";
person maxoumime    schedule 11.02.2017
comment
установлен тег ok, как потом найти этот запрос, скажем, чтобы можно было его отменить? - person sandpat; 27.07.2018

У меня этот код работает

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())
    }
}

Затем отменить по тегу

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")
person Vlad    schedule 31.07.2019