配置
转换器
转换器可以被添加到支持其他类型。六兄弟模块适应流行的序列化库为您提供方便。
Converters can be added to support other types. Six sibling modules adapt popular serialization libraries for your convenience.
Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
直接返回String类型需引入:ScalarsConverterFactory.create()
<span style="font-size:14px;"> retrofit = new Retrofit.Builder() .client(MyOkHttpClient.getMyOkHttpClient().getOkHttpClient())//设置不同的底层网络库 .baseUrl(strBaseUrl) .addConverterFactory(ScalarsConverterFactory.create())//添加 String类型[ Scalars (primitives, boxed, and String)] 转换器 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器 .build();</span>
返回Gson类型需引入:GsonConverterFactory.create()
retrofit = new Retrofit.Builder() .client(MyOkHttpClient.getMyOkHttpClient().getOkHttpClient())//设置不同的底层网络库 .baseUrl(strBaseUrl) .addConverterFactory(GsonConverterFactory.create())//添加 json 转换器 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器 .build();
Retrofit 结合 RxJava使用
-
添加依赖
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxjava:1.1.0'
前两个是 Retrofit 和 Gson 的依赖,第三个是 Retrofit 中 RxJava 转换器的依赖,最后两个就是 RxJava 和 Rx Android 的依赖
-
编写 API
使用 RxJava 的情况下,接口文件稍有修改,接口中的方法的返回类型不再是 Call 而是 Observable 类型:
-
public interface GitHub { @GET("/repos/{owner}/{repo}/contributors") Call<List<Contributor>> contributors(@Path("owner") String owner,@Path("repo") String repo); //使用 RxJava 的方法,返回一个 Observable @GET("/repos/{owner}/{repo}/contributors") Observable<List<Contributor>> RxContributors(@Path("owner") String owner,@Path("repo") String repo); }
结合 RxJava 使用的 接口就定义好了,模型类不需要变动,接下来直接进行网络请求
-
网络请求
使用 RxJava 的 Retrofit 可以直接在 主线程中编写。
-
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Retrofit retrofit=new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory(GsonConverterFactory.create())//添加 json 转换器 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器 .build(); GitHub gitHub=retrofit.create(GitHub.class); gitHub.RxContributors("square","retrofit") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<List<Contributor>>() { @Override public void onCompleted() { Log.i("TAG","onCompleted"); } @Override public void onError(Throwable e) { } @Override public void onNext(List<Contributor> contributors) { for (Contributor c:contributors){ Log.i("TAG","RxJava-->"+c.getLogin()+" "+c.getId()+" "+c.getContributions()); } } }); }
使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求
使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求
OuNews 新闻:RetrofitManager类下的 initOkHttpClient 方法
okhttp3.X,retrofit:2.0.0-beta4适用
1 配置okhttp中的Cache
OkHttpClient okHttpClient; File cacheFile = new File(DemoActivity.this.getCacheDir(), "[缓存目录]"); Cache cache = new Cache(cacheFile, 1024 * 1024 * 10); //100Mb okHttpClient = new OkHttpClient.Builder() .cache(cache) .build();
<pre name="code" class="java"> // 完成缓存 public class MyOkHttpClient { //设缓存有效期为两天 protected static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2; //查询缓存的Cache-Control设置,为if-only-cache时只查询缓存而不会请求服务器,max-stale可以配合设置缓存失效时间 protected static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC; //查询网络的Cache-Control设置,头部Cache-Control设为max-age=0时则不会使用缓存而请求服务器 protected static final String CACHE_CONTROL_NETWORK = "max-age=0"; private String TAG = "MyOkHttpClient"; private OkHttpClient okHttpClient; private static MyOkHttpClient myOkHttpClient; public static MyOkHttpClient getMyOkHttpClient() { if (myOkHttpClient == null) { myOkHttpClient = new MyOkHttpClient(); } return myOkHttpClient; } /** * 初始化 * * @param mContext */ public void init(final Context mContext) { if (okHttpClient != null) { return; } Log.e(TAG, "初始化okHttpClient"); // 因为BaseUrl不同所以这里Retrofit不为静态,但是OkHttpClient配置是一样的,静态创建一次即可 File cacheFile = new File( mContext.getCacheDir(), "HttpCache" ); // 指定缓存路径 Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); // 指定缓存大小100Mb // 云端响应头拦截器,用来配置缓存策略 Interceptor rewriteCacheControlInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!NetUtil.isConnected(mContext)) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE).build(); Log.e(TAG, "no network"); } Response originalResponse = chain.proceed(request); if (NetUtil.isConnected(mContext)) { //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置 String cacheControl = request.cacheControl().toString(); return originalResponse.newBuilder() .header("Cache-Control", cacheControl) .removeHeader("Pragma").build(); } else { return originalResponse.newBuilder().header("Cache-Control", "public, only-if-cached," + CACHE_STALE_SEC) .removeHeader("Pragma").build(); } } }; okHttpClient = new OkHttpClient.Builder().cache(cache) .addNetworkInterceptor(rewriteCacheControlInterceptor) .addInterceptor(rewriteCacheControlInterceptor) .connectTimeout(30, TimeUnit.SECONDS).build(); } public OkHttpClient getOkHttpClient() { return okHttpClient; } /** * 根据网络状况获取缓存的策略 * * @return */ @NonNull public static String getCacheControl(Context mContext) { return NetUtil.isConnected(mContext) ? CACHE_CONTROL_NETWORK : CACHE_CONTROL_CACHE; } }
2 配置请求头中的cache-control
//使用 RxJava 的方法,返回一个 Observable @Headers("Cache-Control: public, max-age=3600") @GET("/repos/{owner}/{repo}/contributors") Observable<List<Contributor>> RxContributors(@Path("owner") String owner,@Path("repo") String repo);
3 配置请求 Retrofit 设置不同的底层网络库
Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl("https://api.github.com") .addConverterFactory(GsonConverterFactory.create())//添加 json 转换器 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器 .build();
4 开启打印连接日志
/** * 开启打印连接日志 * @return */ private HttpLoggingInterceptor getHttpLoggingInterceptor() { boolean isDebug= false;//是否开启 HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); if(isDebug) { interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); } //开启打印连接日志 return interceptor; } OkHttpClient.Builder().addInterceptor(getHttpLoggingInterceptor()) eg: okHttpClient = new OkHttpClient.Builder() .addInterceptor(getHttpLoggingInterceptor()) .cache(cache) .addNetworkInterceptor(rewriteCacheControlInterceptor) .addInterceptor(rewriteCacheControlInterceptor) .connectTimeout(30, TimeUnit.SECONDS).build();
Retrofit 如何使用Observable.from发出多条连接的?
以自己的开源项目 MeiZiNews 中的 ` MzituImgListModel
为栗子,大概是这3步:
- 先向网站请求参数链表
- 使用 flatMap,它可以返回 Observable,所以在 flatMap 里使用 Observable.from
- 再使用 flatMap,在它里面发出单次网络请求连接的 Observable,这时在它返回的就是单次请求的结果了
-
/** * Retrofit 使用Observable.from发出多条连接 * @param context * @param listener * @return */ @Override public Subscription loadWeb(final Context context, final OnModelListener<ImgItem> listener) { MyStringRetrofit.getMyStringRetrofit().init(context, MeiZiApi.MZITU_API); final MzituApi mzituApi = MyStringRetrofit.getMyStringRetrofit().getCreate(MzituApi.class); Observable observable = mzituApi.RxImgList( MyOkHttpClient.getCacheControl(context), imgId, page ).flatMap( new Func1<String, Observable<Integer>>() { @Override public Observable<Integer> call(String s) { // 第一次请求先请求页数,从而获得要发的链接数 Elements mElements = JsoupUtil.getMzituImgPage(s); Elements tempElements = mElements.select("span"); String size = tempElements.get(tempElements.size() - 2).text(); if (TextUtils.isEmpty(size)) { return null; } ArrayList<Integer> numList = new ArrayList<Integer>(); for (int i = 1; i <= Integer.parseInt(size); i++) { numList.add(i); } return Observable.from(numList); } } ).flatMap( new Func1<Integer, Observable<String>>() { @Override public Observable<String> call(Integer integer) { // 发出单次网络请求连接 return mzituApi.RxImgList( MyOkHttpClient.getCacheControl(context), imgId, integer + "" ); } } ).map( new Func1<String, ImgItem>() { @Override public ImgItem call(String s) { // 处理每次请问的结果 ImgItem img = new ImgItem(); Elements mElements = JsoupUtil.getMzituImgItem(s); Element tempElement = mElements.first(); img.setImgUrl(tempElement.select("img").attr("src")); img.setUrl(tempElement.select("img").attr("src")); img.setStory_title(tempElement.select("img").attr("alt")); return img; } } ); return RxJavaUtil.rxIoAndMain( observable, new Subscriber<ImgItem>() { @Override public void onCompleted() { listener.onCompleted(); } @Override public void onError(Throwable e) { listener.onError(e.toString()); DebugUtil.debugLogErr(e, e.toString()); } @Override public void onNext(ImgItem imgItem) { listener.onSuccess(imgItem); } } ); }
问题集
其他笔记
@Path:路径
@Query:查询条件,如:
xx=yy
如果有多个查询条件可以使用: @QueryMap
;