Retrofit 不使用Call时如何将参数作为请求Tag值传递给拦截器
解决方案
错误原因
你自定义的@Tagz注解不属于Retrofit内置支持的参数注解,因此Retrofit在解析接口方法时会认为该参数没有配置合法注解,抛出No Retrofit annotation found异常。
实现方案
你不需要自定义CallAdapter,也不需要修改原有suspend函数的返回结构,直接利用Retrofit内置的Invocation特性即可实现参数级动态Tag传递,步骤如下:
步骤1:保留自定义Tag注解
@Target(AnnotationTarget.VALUE_PARAMETER) @Retention(AnnotationRetention.RUNTIME) annotation class Tagz
步骤2:定义接口方法
和你原有写法保持一致即可:
@GET suspend fun getUsers(@Tagz value: CachePolicy.Type, @Url placeholder: String): Response<UserEntity?>
步骤3:在拦截器中读取Tag值
Retrofit所有请求默认会携带Invocation类型的Tag,其中包含了当前请求对应的方法信息、参数注解、参数实际传入值,直接解析即可:
class CustomTagInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originRequest = chain.request() // 读取Retrofit自动注入的Invocation信息 val invocation = originRequest.tag(Invocation::class.java) ?: return chain.proceed(originRequest) // 遍历所有参数找到标注@Tagz的参数 invocation.method().parameterAnnotations.forEachIndexed { index, annotations -> val tagzAnnotation = annotations.filterIsInstance<Tagz>().firstOrNull() if (tagzAnnotation != null) { // 拿到传入的Tag实际值 val cachePolicy = invocation.arguments()[index] as? CachePolicy.Type // 按需处理,比如将值重新写入Request Tag方便后续其他拦截器使用 val newRequest = originRequest.newBuilder() .tag(CachePolicy.Type::class.java, cachePolicy) .build() return chain.proceed(newRequest) } } return chain.proceed(originRequest) } }
步骤4:注册拦截器
将上述拦截器添加到OkHttpClient的拦截器列表中即可生效。
注意事项
- 该方案依赖Retrofit 2.6.0及以上版本,这是Retrofit支持suspend函数、默认注入Invocation Tag的最低版本要求
- 如果需要传递多个不同类型的Tag,可给
@Tagz添加key字段用于区分不同参数
内容的提问来源于stack exchange,提问作者Ahmad Shahwaiz
相关产品推荐
相关产品推荐

