Retrofit2学习笔记-3

这个笔记会记录一些比较杂的东西,主要是Retrofit2使用中需要注意的要点。

Synchronous vs. Asynchronous
Call instances can be executed either synchronously or asynchronously. Each instance can only be used once, but calling clone() will create a new instance that can be used.
On Android, callbacks will be executed on the main thread. On the JVM, callbacks will happen on the same thread that executed the HTTP request.
  1. 以上是官方网站上的一段介绍,大意就是无论是同步的还是异步的请求Call的实例只能使用一次,如果想继续使用的话,就需要使用Callclone()方法创建一个新的对象去使用。对于Android平台回调会在main线程也就是UI线程实行,所以可以在回调中更新UI。
  2. 如果使用ProGuard混淆代码需要加入以下配置。
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
  1. 可以通过client方法设置Retrofit2的默认OkHttpClient,在设置这个OkHttpClient的时候我们还可以做很多工作,我们先看一下代码。
//创建OkHttpClient
OkHttpClient okHttpClient= new OkHttpClient.Builder()
//添加一个网络拦截器
 .addNetworkInterceptor( new HttpLoggingInterceptor()
//日志级别
.setLevel(HttpLoggingInterceptor.Level.HEADERS))
//设置cookie管理器
.cookieJar(new NovateCookieManger(context)) 
.addInterceptor(new BaseInterceptor(mContext))
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(url)
.build();

首先创建OkHttpClient的时候可以使用addNetworkInterceptor方法添加一个网络拦截器。这里使用了一个日志拦截器HttpLoggingInterceptor它可以打印OKHttp的request和response的数据。要使用这个类需要引入依赖。

compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'

简单介绍一下这个拦截器,基本的使用方法就是这样。

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BASIC);
OkHttpClient client = new OkHttpClient.Builder() 
.addInterceptor(logging)
.build();

setLevel方法设置日志级别,NONE没有日志、BASIC基础日志(request 和 response 的信息)、HEADERS请求头信息(除了 request 和 response 的信息外还有各自的headers)、BODY请求体信息(除了 request 和 response 的信息外还有各自的headers以及各自的body),我们可以根据自身的需要进行设置。并且在任何时刻都可以通过setLevel方法重新设置日志级别。如果希望打印的日志做一些本地化的工作,可以在创建HttpLoggingInterceptor对象的时候可以在构造器中传入一个Logger的实例,方法参考下面代码。

HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
    @Override    public void log(String message) {
        Log.d("OkHttp",message);
    }
});

这样我们的日志输出都是debug,并且tag都是"OkHttp"。
再来看一下cookieJar方法,这个方法可以为OkHttpClient设置一个Cookie的管理者。它接收一个实现CookieJar接口的类的对象。我们看一下CookieJar接口的源码:

public interface CookieJar {
  /** A cookie jar that never accepts any cookies. */
  CookieJar NO_COOKIES = new CookieJar() {
    @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
    }
    @Override public List<Cookie> loadForRequest(HttpUrl url) {
      return Collections.emptyList();
    }
  };
  /**
   * Saves {@code cookies} from an HTTP response to this store according to this jar's policy.
   * 
  * <p>Note that this method may be called a second time for a single HTTP response if the response 
  * includes a trailer. For this obscure HTTP feature, {@code cookies} contains only the trailer's
   * cookies.
   */
  void saveFromResponse(HttpUrl url, List<Cookie> cookies);
  /**
   * Load cookies from the jar for an HTTP request to {@code url}. This method returns a possibly
   * empty list of cookies for the network request. 
  *
   * <p>Simple implementations will return the accepted cookies that have not yet expired and that 
  * {@linkplain Cookie#matches match} {@code url}. 
  */
  List<Cookie> loadForRequest(HttpUrl url);
}

它的内部有一个实现NO_COOKIES是当当前的请求没有Cookie的时候使用的,剩下两个方法saveFromResponseloadForRequest一看便知,一个是保存Response返回的Cookie一个是向Request请求添加Cookie的。具体的使用可以参考如下代码:

OkHttpClient client = new OkHttpClient.Builder()
    .cookieJar(new CookieJar() {
        private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();

        @Override
        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
            cookieStore.put(url, cookies);
        }

        @Override
        public List<Cookie> loadForRequest(HttpUrl url) {
            List<Cookie> cookies = cookieStore.get(url);
            return cookies != null ? cookies : new ArrayList<Cookie>();
        }
    })
    .build();

OkHttpClient的源码可以知道,其实cookieJar方法设置的是OkHttpClient对象中的一个属性,所以当我们使用这个OkHttpClient对象作为网络请求客户端的时候,这个Cookie管理者会一直起作用。
我们再来看一下addInterceptor方法:

public Builder addInterceptor(Interceptor interceptor)

它接收一个实现了Interceptor接口的对象,看一下Interceptor源码:

public interface Interceptor {
      Response intercept(Chain chain) throws IOException;
      interface Chain {
        Request request();
        Response proceed(Request request) throws IOException;
        Connection connection();
    }
}

其中intercept方法是拦截器的逻辑实现,我们可以在这个方法里面对请求和应答做处理。请看下面的例子:

/** This interceptor compresses the HTTP request body. Many Webservers can't handle this! */
final class GzipRequestInterceptor implements Interceptor {
        @Override public Response interceptor(Interceptor.Chain chain) thorws IOException {
                 Request originalRequest = chain.request();
                 if (originalRequest.body() == null || originalRequest.header("Content-Encoding")) {
                         return chain.proceed(originalRequest);
                 }
                 Request comressedRequest = originalRequest.newBuilder() .header("Content-Encoding", "gzip") .method(originalRequest.method(), gzip(originalRequest.body())) .build();
                 return chain.proceed(compressedRequest);
         }
         private RequestBody gzip(final RequestBody body) {
                 return new RequestBody() {
                         @Override
                         public MediaType contentType() {
                                 return body.contentType();
                         }
                         @Override
                         public long contentLength() {
                                 return -1;
                                 // We don't know the compressed length in adcance!
                         }
                         @Override
                         public void wirteTo(BufferedSink sink) throws IOException {
                                 BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
                                 body.writeTo(gzipSink);
                                 gzipSink.close();
                        } 
                };
         }
}

我们可以看到比较关键的几个点,可以通过interceptor方法的入参chain.request()获取Request,然后chain.proceed(originalRequest)方法可以将请求继续执行,并返回应答。我们可以通过这个拦截器对请求和应答进行一些处理。
还有connectTimeout方法,不用多说这个方法是设置网络连接超时的,还有一个上面没有提到的方法retryOnConnectionFailure(boolean retryOnConnectionFailure)可以通过这个方法来设置是否在连接失败的时候重试。

                                   ------------未完待续
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容