文章地址 :https://gank.io/post/56e80c2c677659311bed9841
http://gank.io/post/560e15be2dca930e00da1083#toc_14
文章:https://www.jianshu.com/p/0d1fb9f08a34
添加公共参数
实际项目中,每个接口都有一些基本的相同的参数,我们称之为公共参数,比如:userId、userToken、userName、deviceId等等,我们不必每个接口都去写,可以写一个拦截器,在拦截器里面拦截请求,为每个请求都添加相同的公共参数。
拦截器代码如下:
/*
* 拦截器
*
* 向请求头里添加公共参数
*/
public class HttpCommonInterceptor implements Interceptor {
private Map<String,String> mHeaderParamsMap = new HashMap<>();
public HttpCommonInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Log.d("HttpCommonInterceptor","add common params");
Request oldRequest = chain.request();
// 添加新的参数,添加到url 中
/*HttpUrl.Builder authorizedUrlBuilder = oldRequest.url().newBuilder()
.scheme(oldRequest.url().scheme())
.host(oldRequest.url().host());*/
// 新的请求
Request.Builder requestBuilder = oldRequest.newBuilder();
requestBuilder.method(oldRequest.method(), oldRequest.body());
//添加公共参数,添加到header中
if(mHeaderParamsMap.size() > 0){
for(Map.Entry<String,String> params:mHeaderParamsMap.entrySet()){
requestBuilder.header(params.getKey(),params.getValue());
}
}
Request newRequest = requestBuilder.build();
return chain.proceed(newRequest);
}
public static class Builder{
HttpCommonInterceptor mHttpCommonInterceptor;
public Builder(){
mHttpCommonInterceptor = new HttpCommonInterceptor();
}
public Builder addHeaderParams(String key, String value){
mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
return this;
}
public Builder addHeaderParams(String key, int value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, float value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, long value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, double value){
return addHeaderParams(key, String.valueOf(value));
}
public HttpCommonInterceptor build(){
return mHttpCommonInterceptor;
}
}
}
以上就是添加公共参数的拦截器,在 RetrofitServiceManager 类里面加入OkHttpClient 配置就好了。
代码如下:
// 添加公共参数拦截器
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
.addHeaderParams("paltform","android")
.addHeaderParams("userToken","1234343434dfdfd3434")
.addHeaderParams("userId","123445")
.build();
builder.addInterceptor(commonInterceptor);
作者:God丶Eye
链接:https://www.jianshu.com/p/0ad99e598dba
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
这个是retrofit的一个接口请求的步骤。
1.单纯的retrofit请求
//进行网络请求
private void getMovie(){
String baseUrl = "https://api.douban.com/v2/movie/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
MovieService movieService = retrofit.create(MovieService.class);
Call<MovieEntity> call = movieService.getTopMovie(0, 10);
call.enqueue(new Callback<MovieEntity>() {
@Override
public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
resultTV.setText(response.body().toString());
}
@Override
public void onFailure(Call<MovieEntity> call, Throwable t) {
resultTV.setText(t.getMessage());
}
});
}
以上为没有经过封装的、原生态的Retrofit写网络请求的代码。 我们可以封装创建Retrofit和service部分的代码,然后Activity用创建一个Callback作为参数给Call,这样Activity中只关注请求的结果,而且Call有cancel方法可以取消一个请求,好像没Rxjava什么事了,我觉得可以写到这就下班了~
2.retrofit和rxjava之间的关系
Retrofit本身对Rxjava提供了支持。
添加Retrofit对Rxjava的支持需要在Gradle文件中添加
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
然后在创建Retrofit的过程中添加如下代码:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
这样一来我们定义的service返回值就不在是一个Call了,而是一个Observable
重新定义MovieService
public interface MovieService {
@GET("top250")
Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
}
3. 如何返回统一的数据
按照我们之前的用法,使用Gson转型需要我们在创建subscriber对象是指定返回值类型,如果我们对不同的返回值进行封装的话,那可能就要有上百个Entity了,看着明明是很清晰的结构,却因为data的不确定性无奈了起来。
少年,不必烦恼,来来来~ 老衲赐你宝典葵花,老衲就是练了这个才出家。。。
我们可以创建一个HttpResult类
public class HttpResult<T> {
private int resultCode;
private String resultMessage;
private T data;
}
如果data是一个User对象的话。那么在定义Service方法的返回值就可以写为
Observable<HttpResult<User>>
这样一来HttpResult就相当于一个包装类,将结果包装了起来,但是在使用的时候要给出一个明确的类型。
4.什么叫包装类
包装类即使把基本类型变成对象类型
像ArrayList这样的集合是不能储存基本类型的只能储存对象 为了方便这些集合的使用所以才有了把基本类型包装成对象类型
ArrayList<Integer> al = new ArrayList<Integer>();
Integer i = 1;
al.add(i);
//直接把数字写进去也可以
al.add(2);
ArrayList<Integer> al = new ArrayList<Integer>();
Integer i = 1;
al.add(i);
//直接把数字写进去也可以
al.add(2);
包装类,把基本类型转换成对象
泛型的参数不能是基本是基本数据类型(int 、char等)。
泛型是新的类型,可以指定多个类型参数,成为新的不同的类型
包装类和泛型 的区别 包装类把基本类型转换成对象, 泛型,可以是新的对象,例如UserEntity等。
5.
安卓6.0 之后 很多权限需要动态申请, 动态申请权限 ,
6. 统一处理错误信息 ,如何统一处理错误信息
我们在resultCode != 0
的时候,抛出个自定义的ApiException。这样就会进入到subscriber的onError中,我们可以在onError中处理错误信息。
抛出自定义的异常 ,这样就会进入到 subscriber的onError中
当code!=0 或者 数据为空啊,等情况 抛出异常,然后在onError中处理异常, 然后设置当前的页面是哪一个, 是没网是空,还是加载失败。
@Override
public void onError(Throwable e) {
if (mMultipleStatusView.getViewStatus() != MultipleStatusView.STATUS_CONTENT) {
if (EmptyException.EMPTY_MSG.equals(e.getMessage())) {//在这里处理异常
mMultipleStatusView.showEmpty();
} else {
mMultipleStatusView.showError();
}
}
}
@Override
public void onNext(BaseEntity<RankMemberListEntity> rankListEntity) {
app.setServerTime(rankListEntity.server_time);
if (HttpConstant.REQUEST_SUCCESS_CODE == rankListEntity.code) {
if (rankListEntity.data.rankList == null || rankListEntity.data.rankList.size() == 0) {
throw new EmptyException();//抛出自定义的异常
}
} else {
RecyclerViewStateUtils.setFooterViewState(PaiHangActivity.this, mRecyclerView, Constant.REQUEST_COUNT, LoadingFooter.State.NetWorkError, mFooterClick);
throw new RequestException();//抛出自定义的异常
}
}
});
7. 先将 retrofit 和rxjava两者结合, 然后再封装请求的方法
两者结合的代码:
//进行网络请求
private void getMovie(){
String baseUrl = "https://api.douban.com/v2/movie/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
MovieService movieService = retrofit.create(MovieService.class);
movieService.getTopMovie(0, 10)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<MovieEntity>() {
@Override
public void onCompleted() {
Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(Throwable e) {
resultTV.setText(e.getMessage());
}
@Override
public void onNext(MovieEntity movieEntity) {
resultTV.setText(movieEntity.toString());
}
});
}
下面是对 请求这边的一个封装 , (单例 )
问一下,单例模式怎么写
淘头条中:
public static ApiService getInstance(Context mContext) {
if (service == null) {
synchronized (ApiService.class) {
if (service == null) {
service = new ApiService(mContext.getApplicationContext());
}
}
}
return service;
}
另外别的项目中:
//在访问HttpMethods时创建单例
private static class SingletonHolder{
private static final HttpMethods INSTANCE = new HttpMethods();
}
//获取单例
public static HttpMethods getInstance(){
return SingletonHolder.INSTANCE;
}
8.关于包装类返回数据
这样一来HttpResult就相当于一个包装类,将结果包装了起来,但是在使用的时候要给出一个明确的类型。
public class HttpResult<T> {
private int resultCode;
private String resultMessage;
private T data;
}
9.关于rxjava
与传统观察者模式不同, RxJava 的事件回调方法除了普通事件 onNext()
(相当于 onClick()
/ onEvent()
)之外,还定义了两个特殊的事件:onCompleted()
和 onError()
。
onCompleted()
: 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的onNext()
发出时,需要触发onCompleted()
方法作为标志。onError()
: 事件队列异常。在事件处理过程中出异常时,onError()
会被触发,同时队列自动终止,不允许再有事件发出。- 在一个正确运行的事件序列中,
onCompleted()
和onError()
有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted()
和onError()
二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
onCompleted ()和onError() 两者 只有一个执行 , 并且是最后一个; 走onNext ()再走 onComplete()
10.rxjava订阅这里
Onserver也总会先被转换成一个 Subseriber再使用
RxJAVA中Observer/subscriber 接口的实现方式
Observer<String> observer = new Observer<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
}
@Override
public void onCompleted() {
Log.d(tag, "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
Subscribe (订阅)
创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来,整条链子就可以工作了。代码形式很简单:
observable.subscribe(observer);//
或者:
observable.subscribe(subscriber);
10.rxjava 的 异步 通过 scheduler (调度器)进行控制
Schedulers.io()
: I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的Scheduler
。行为模式和newThread()
差不多,区别在于io()
的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()
比newThread()
更有效率。不要把计算工作放在io()
中,可以避免创建不必要的线程。
* Android 还有一个专用的 AndroidSchedulers.mainThread()
,它指定的操作将在 Android 主线程运行。
被观察者.subscribe(观察者) 这是一个观察者模式
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(观察者);
有了这几个 Scheduler
,就可以使用 subscribeOn()
和 observeOn()
两个方法来对线程进行控制了。 * subscribeOn()
: 指定 subscribe()
所发生的线程,即 Observable.OnSubscribe
被激活时所处的线程。或者叫做事件产生的线程。 * observeOn()
: 指定 Subscriber
所运行在的线程。或者叫做事件消费的线程。
文字叙述总归难理解,上代码:
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())
的指定,被创建的事件的内容 1
、2
、3
、4
将会在 IO 线程发出;而由于 observeOn(AndroidScheculers.mainThread()
) 的指定,因此 subscriber
数字的打印将发生在主线程 。事实上,这种在 subscribe()
之前写上两句 subscribeOn(Scheduler.io())
和 observeOn(AndroidSchedulers.mainThread())
的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。
subscribeOn是 发生在哪个线程, io线程的话,便于读取数据,且线程数量无上限
observeOn 是回调的方法在哪个线程处理,消费 主线程
(Schedulers)调度器的几种方法:
Schedulers.immediate()
: 直接在当前线程运行,相当于不指定线程。这是默认的Scheduler
。Schedulers.newThread()
: 总是启用新线程,并在新线程执行操作。Schedulers.io()
: I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的Scheduler
。行为模式和newThread()
差不多,区别在于io()
的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下io()
比newThread()
更有效率。不要把计算工作放在io()
中,可以避免创建不必要的线程。Schedulers.computation()
: 计算所使用的Scheduler
。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个Scheduler
使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在computation()
中,否则 I/O 操作的等待时间会浪费 CPU。- 另外, Android 还有一个专用的
AndroidSchedulers.mainThread()
,它指定的操作将在 Android 主线程运行。
这一下就知道了 , btn是被观察者 , onClickListener 是 观察者 setOnclicklistener 是订阅
一年至少要看两三百本书 , 那么 ,平均 一天多点就是一本书
观察者要放在主线程 ,
如果被点击了,去告知 ; 小偷拿了东西告诉警察
这个接口的调度,
就可以使用 subscribeOn()
和 observeOn()
两个方法来对线程进行控制了。
* subscribeOn()
: 指定 subscribe()
所发生的线程,即 Observable.OnSubscribe
被激活时所处的线程。或者叫做事件产生的线程。在子线程中,订阅发生在哪个线程
* observeOn()
: 指定 Subscriber
所运行在的线程。或者叫做事件消费的线程。 就是onCompleted(),onNext()这几个方法
observable.subscribeOn(Schedulers.io()) 订阅,被激活 发生在哪个线程,子线程下载数据,查阅数据库和网络数据。
.observeOn(AndroidSchedulers.mainThread())这句话说明,三个方法里面(,onNext()等)的内容是放在主线程的
.subscribe()
文字叙述总归难理解,上代码:
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())
的指定,被创建的事件的内容 1
、2
、3
、4
将会在 IO 线程发出;而由于 observeOn(AndroidScheculers.mainThread()
) 的指定,因此 subscriber
数字的打印将发生在主线程 。事实上,这种在 subscribe()
之前写上两句 subscribeOn(Scheduler.io())
和 observeOn(AndroidSchedulers.mainThread())
的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。
在subscribe( )之前写上两句 subscribeOn(Scheduler.io( ))和 onserveOn(AndroidSchedulers.mainThread)的这种方式非常常见,它适用于多数的 {后台线程取数据,主线程显示} 的程序策略。