【问题标题】:Retrofit Adding tag to the original request object改造将标签添加到原始请求对象
【发布时间】:2017-02-06 11:39:29
【问题描述】:

我正在尝试解决一个问题,我将进行几个异步调用,并根据原始请求执行一项任务。为了解决这个问题,我尝试为每个请求添加一个标签,然后在成功响应后,我可以获取标签并根据标签采取行动。在这里,我只使用 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());
                    }
                });

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

【问题讨论】:

    标签: android retrofit2 okhttp3


    【解决方案1】:

    这个解决方案显然是一个 hack,但它确实有效。

    假设您像这样创建改造服务:

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

    您需要向 Retrofit 实例添加一个新的 CallFactory,因此它每次都会添加一个标签。由于标签是只读的,我们将使用一个只包含一个元素的 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";
    

    【讨论】:

    • ok 标记已设置,以后如何找到这个请求,比如说能够取消它?
    【解决方案2】:

    对我来说,这段代码是有效的

    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")
    

    【讨论】:

      【解决方案3】:

      请求上已经有标签。您可以通过以下代码获取:

      val invocation: Invocation? = call.request().tag(Invocation::class.java)
              if (invocation != null) {
                  Timber.d("tag--${invocation.method().name}}-------${invocation.arguments()}")
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-18
        • 2018-12-27
        • 2010-09-24
        • 1970-01-01
        • 2016-11-20
        相关资源
        最近更新 更多