最近公司要搬上海,可是不想去,就写个东东玩玩,其实也是东抄西凑的,合成的。纯粹的玩。。。。。
先来简单了解下
RxJava,RxJava到底是什么?RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库),这就是 RxJava 。
RxJava的简单应用,可以认为RxJava是一种观察者模式,举一个Android中的例子,就是Button, OnClick(View),OnClickListener,自行脑补。在RxJava中,被观察者叫做:Observable ;观察者叫做:Observer 或者Subscriber(是Observer 的一个抽象类);订阅(注册)叫做Subscribe;连接起来就是下面这行代码:
Observable.Subscriber(Observer);
虽然看起来反了,但是就是这么写的。这个网络请求框架中,还只要一个东西就行了,那就是
Scheduler 。下面来讲一下
Scheduler 是什么?
在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。好了,就用一段代码解释,请看:
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});
subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程,observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程。
Retrofit是什么?为什么android这么流行用Retrofit?先来看一段文字:
随着Google对HttpClient 摒弃,和Volley的逐渐没落,OkHttp开始异军突起,而Retrofit则对okHttp进行了强制依赖。Retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端,如果看源码会发现其实质上就是对okHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口请求的底层,其将请求返回javaBean,对网络认证 REST API进行了很好对支持此,使用Retrofit将会极大的提高我们应用的网络体验。
下面结合代码来看Retrofit和OkHttp的使用步骤:
1,首先,要使用Retrofit ,你肯定需要把它的包引入,在你的build.gradle文件中添加如下配置:
compile 'com.squareup.retrofit2:retrofit:2.1.0'//retrofit
compile 'com.google.code.gson:gson:2.6.2'//Gson 库
compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'//转换器,请求结果转换成Model
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'//配合Rxjava 使用
2,创建一个Retrofit 实例,并且完成相关的配置
public static final String BASE_URL = "https://api.douban.com/v2/movie/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
说明:配置了接口的baseUrl和一个converter,GsonConverterFactory 是默认提供的Gson 转换器,Retrofit 也支持其他的一些转换器,详情请看官网Retrofit官网
3,创建一个 接口 ,代码如下:
public interface MovieService {
//获取豆瓣Top250 榜单
@GET("top250")
Call<MovieSubject> getTop250(@Query("start") int start,@Query("count")int count);
}
说明:定义了一个方法getTop250,使用get请求方式,加上@GET 标签,标签后面是这个接口的 尾址top250,完整的地址应该是 baseUrl+尾址 ,参数 使用@Query标签,如果参数多的话可以用@QueryMap标签,接收一个Map ,还有Post方式请自行百度。
4,用Retrofit 创建 接口实例 MoiveService,并且调用接口中的方法进行网络请求,代码如下:
//获取接口实例
MovieService MovieService movieService = retrofit.create(MovieService.class);
//调用方法得到一个Call
Call<MovieSubject> call = movieService.getTop250(0,20);
//进行网络请求
call.enqueue(new Callback<MovieSubject>() {
@Override
public void onResponse(Call<MovieSubject> call, Response<MovieSubject> response) {
mMovieAdapter.setMovies(response.body().subjects);
mMovieAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<MovieSubject> call, Throwable t) {
t.printStackTrace();
}
});
以上就是一个使用Retrofit 完成一个网络请求的完整示例,其他标签使用方式请看官网Retrofit官网,官网用法也介绍的比较详细,此外,发现了一篇博客也介绍得比较详细,Retrofit用法详解
在了解了RxJava 和 Retrofit相关知识之后,再看一下
如何配合使用:
1, 更改定义的接口,返回值不再是一个Call ,而是返回的一个Observble.
public interface MovieService {
//获取豆瓣Top250 榜单
@GET("top250")
Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
}
创建Retrofit 的时候添加如下代码
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
添加转换器Converter(将json 转为JavaBean)
addConverterFactory(GsonConverterFactory.create())
最终在Activity中使用如下代码:
Subscription subscription = movieService.getTop250(0,20) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<MovieSubject>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(MovieSubject movieSubject) { } });
关于onCompleted,onError,onNext请自行百度了解。
关于OkHttp的配置简单说一点,其他的可以看相关文档:
通过OkHttpClient 可以配置很多东西,比如链接超时时间,缓存,拦截器等等。代码如下:
// 创建 OKHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
builder.writeTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//写操作 超时时间
builder.readTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//读操作超时时间
// 添加公共参数拦截器
BasicParamsInterceptor basicParamsInterceptor = new BasicParamsInterceptor.Builder()
.addHeaderParam("userName","")//添加公共参数
.addHeaderParam("device","")
.build();
builder.addInterceptor(basicParamsInterceptor);
// 创建Retrofit
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.build();
缓存使用
其实,OkHttp已经给我们做好了缓存,不过只支持Get方式,不支持Post,别问为什么,这是由Http标准规定,Get用来获取数据,Post用来更改服务器数据,只返回状态,状态一般是不需要缓存的。
但是我们发现,一般后台给的接口都是Post方式。那么就需要自己实现缓存机制了。
我们先来讲一下第一种缓存方式,OkHttp支持的Get获取数据缓存,OkHttp配置时候有两个拦截器
okHttpClient.networkInterceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR);
okHttpClient.interceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR);
我们只姚自定义拦截器就行了:
/**
* 云端响应头拦截器,用来配置缓存策略
* Dangerous interceptor that rewrites the server's cache-control header.
*/
private final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = chain -> {
Request request = chain.request();
if(!NetUtils.hasNetwork(context)){
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
Logger.t(TAG).w("no network");
}
Response originalResponse = chain.proceed(request);
if(NetUtils.hasNetwork(context)){
//有网的时候读接口上的@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, max-stale=2419200")
.removeHeader("Pragma")
.build();
}
};
最后来讲下,自己解决Get Post请求的网络数据缓存。
1.在OkHttp自定义的拦截器中,获取Response对象Body的内容,以Key value 的方式存储到本地缓存,key为实际请求的URL地址,Value为Body的内容。
2.重写Subscriber,用代码解释如下:
public abstract class OnRequestCallback<T> extends Subscriber<T> {
public String cacheKey;//缓存key
public boolean userCache = false;//缓存开启开关
public Class dataClassName;
@Override
public void onStart() {
}
@Override
public final void onCompleted() {
}
@Override
public final void onError(Throwable erroe)
{
if ( !userCache || NetUtil.isNetworkAvailable(AppConfig.mContext)) {
//不使用缓存 或者网络可用 的情况下直接回调onFailure
onFailed(erroe.getMessage());
return;
}
String cache = CacheManager.getInstance().getCache(cacheKey);
Log.e("获取缓存", "get cache->" + cache);
if (!TextUtils.isEmpty(cache) && dataClassName != null) {
Object obj = new Gson().fromJson(cache, dataClassName);
if (obj != null) {
onResponse((T) obj);
}
}else{
onFailed(erroe.getMessage());
}
}
@Override
public final void onNext(T response)
{
onResponse(response);
}
public abstract void onFailed(String message);
public abstract void onResponse(T response);
/**
* 设置是否开启缓存 默认关闭
* @param userCache
*/
public void setUserCache(boolean userCache) {
this.userCache = userCache;
}
/**
* 设置缓存获取的Key,用请求地址作为 key
* @param url
*/
public void setCacheKey(String url) {
this.cacheKey = AppConfig.basicUrl +url;
}
/**
*设置数据模型,解析缓存数据
* @param dataClassName
*/
public void setClassName(Class dataClassName) {
this.dataClassName = dataClassName;
}
}
关于缓存框架,我用的是
DiskLruCache.
好了,以上就是RxJava+Retrofit+OkHttp+网络缓存的简单讲解。