引言
hello 大家好,没想到吧!我又回来了,回来了,来了,了(武器大师的话,我加了个特技,哈哈)。
好了开始我们今天的主题吧,昨天有人问我,该用什么网络框架,怎么用,怎么保证内存不泄露?
看到这个,我还是很激动的,毕竟是我写博客到现在第一个问我的问题。
那好,我就拿我经常用的网络框架(Retrofit),慢慢欣赏吧(买好瓜子哈)。
OKHTTP
总结一句话-->"略",哈哈,别打我,我还是个孩子。
这个不是今天的重点,而且这个东西出来这么久了,大家估计都用了,所以我就不讲了,大家自己脑补吧(google)。
Retrofit版本介绍
Retrofit是squareup公司完成的一个很吊的开源的网络框架,为什么这样说呢?,因为大家都说好啊。
其实这里我也想略的,但是又觉得不好意思,所以这次我扔个连接给你们,接住哈!!!
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0915/3460.html
Retrofit2使用
想必大家看了上面的文章,肯定不会再去使用retrofit1.X版本了,所以我直接就讲Retrofit2.X喽,好了,开始啦!!!
首先创建一个新的工程(名字随便你们喽)打开app/build.gradle(感觉有点多余哈,哈哈),在dependencies节点下面添加
(当然大家可以不按照我这个来)
//compile ‘com.squareup.retrofit2:retrofit:2.1.0‘
//retrofit2 转化器 gson
compile ‘com.squareup.retrofit2:converter-gson:2.1.0‘
//引进Rxjava2.0
compile ‘io.reactivex.rxjava2:rxandroid:2.0.0‘
//log拦截器
compile ‘com.squareup.okhttp3:logging-interceptor:3.3.0‘
注意:一定要保证添加的版本相同,要不然会有重复包或者冲突呦,直接按照我这个来得了哈,安全,绿色,多好啊。
这里呢大家可能看到了,我为什么把retrofit2.1.0注释掉了?
因为大部分我们都是使用Gson解析,我就直接引入了converter-gson。
这个就是可以直接把返回的数据通过gson解析成对象(都懂的)。
我们打开此包的pom文件(看下面),他已经引进了retrofit2.0版本,所以就不需要喽,以下同理哈(rxandroid- rxjava)
好了,大家可能也看到我也引进Rxjava2(rxandroid:2.0.0)了,这个留到最后。包引进之后呢,下面就可以撸代码了。
我们创建一个NetClient.java,大家看名字就知道了,好了直接上代码
package com.lingchen.netretrofit.net;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Author lingchen
* Email [email protected]
* Time 2016/11/4
* Function 网络客户端
*/
public class NetClient {
//暂时放在这里
private static final String URL = "http://bobo.yimwing.com";
/**
* 获取Retrofit适配器。
*
* @return 网络适配器
*/
public static Retrofit newRetrofit() {
return new Retrofit.Builder().baseUrl(URL).client(getClient().build())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
/**
* 获取 OkHttpClient
*
* @return OkHttpClient
*/
public static OkHttpClient.Builder getClient() {
return new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(300, TimeUnit.SECONDS)
.addInterceptor(new HttpLoggingInterceptor());//日志
}
}
嗯,比较简单的,注释也很清楚哈。现在我们来写一个接口(不要问为什么哈,因为retrofit就是这样规定的,嘻嘻)。
package com.lingchen.netretrofit.net;
/**
* Author lingchen
* Email [email protected]
* Time 2016/11/4
* Function 网络接口 Retrofit().create()
*/
public interface ComInterface {
}
我们再来写一个类,来存放Retrofit实例。
/**
* Author lingchen
* Email [email protected]
* Time 2016/11/4
* Function 网络通用接口
*/
public class ComApi {
public static ComApi comApi;
private ComInterface mComInterface;
public static ComApi getInstance() {
synchronized (ComApi.class) {
if (comApi == null) {
comApi = new ComApi();
}
}
return comApi;
}
private ComApi() {
mComInterface = NetClient.newRetrofit().create(ComInterface.class);
}
}
好了这里大家可以看到了,此类为单例模式,而且含有retrofit创建出来的mComInterface(这就是retrofit的强大之后了)。
相比以前做过后台,使用过SpringMVC大家肯定会觉得很熟悉,貌似现在还看不出来,哈哈,别着急,现在还不是没有请求吗?)
准备工作准备了,我们开始来写个请求吧,这是我从公司挑来的,好,我们看下接口
http://bobo.yimwing.com/api/version/android_new
当我们拿到这个接口的时候,我们就应该去浏览器看看喽
{“code”:1,”data”:{“versionName”:”1.3.0”,”versionCode”:4,”isQiangzhi”:1,”url”:”http:\/\/bobo-sql.oss-cn-beijing.aliyuncs.com\/app-bobo-release.apk”,”updateContent”:”重要版本更新!”}}
这个就是大家常见的json数据啦,我们使用AS一个插件(GsonFormat)具体安装大家可以google哈。我已经安装了,我直接用啦
很明了吧?可以看到code=1肯定就是成功了,data里面存放就是版本的内容了,我们直接点击ok(要预先创建一个新类哈)
这里我们就要说下了,从这里就可以看到,后台返回的固定格式是int code,Object data(其实应该还有String msg,只是这个接口没返回而已)这里我之所以用Object,是因为不可能所有的返回类型都是我们版本数据,所以我们就要开始提取了
package com.lingchen.netretrofit.net;
/**
* Author lingchen
* Email 838878458@qq.com
* Time 2016/11/4
* Function 数据响应模型
*/
public class ResBaseModel<T> {
private static final int CODE_SUCCESS = 1;
/**
* data : {}
* code : 1
* msg : 操作成功
*/
private int code;
private String msg;
protected T data;
public String getMsg() {
return msg;
}
public T getData() {
return data;
}
public boolean isSuccess() {
return CODE_SUCCESS == code;
}
}
package com.lingchen.netretrofit.net.model;
/**
* Author lingchen
* Email [email protected]
* Time 2016/11/4
* Function 版本信息
*/
public class VersionModel {
/**
* versionName : 1.3.0
* versionCode : 4
* isQiangzhi : 1
* url : http://bobo-sql.oss-cn-beijing.aliyuncs.com/app-bobo-release.apk
* updateContent : 重要版本更新!
*/
private String versionName;
private int versionCode;
private int isQiangzhi;
private String url;
private String updateContent;
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public int getVersionCode() {
return versionCode;
}
public void setVersionCode(int versionCode) {
this.versionCode = versionCode;
}
public int getIsQiangzhi() {
return isQiangzhi;
}
public void setIsQiangzhi(int isQiangzhi) {
this.isQiangzhi = isQiangzhi;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUpdateContent() {
return updateContent;
}
public void setUpdateContent(String updateContent) {
this.updateContent = updateContent;
}
}
好了,我把我现在的架构发下
好了(大家肯定没看到CheckVErsionActivity,肯定没看到,谁会想到我事先做了测试,哈哈,也没办法,毕竟用了Rxjava2.0,上个月刚出来,太多坑哈)。
下面开始写我们的接口了,首先我们打开我们的ComInterface,在里面写下如下代码
@GET("/api/version/android_new")
Call<ResBaseModel<VersionModel>> checkVersion();
使用过SpringMVC的兄弟们,是不是感觉很亲近啊?哈哈,一开始我也是觉得很亲切,毕竟我还搞过半年的后台,好吧跑题了。
接下来我们在ComApi写上一个方法
/**
* 检测版本
*
* @return 回调
*/
public Call<ResBaseModel<VersionModel>> checkVersion() {
return mComInterface.checkVersion();
}
好了,也没啥东西,这里可能对retrofit没有太多的讲解,不懂的兄弟可以自行去google哈(见谅哈)
我们现在写个activity来试试吧
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="start"
android:text="请求" />
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:hint="请求结果" />
</LinearLayout>
/**
* Author lingchen
* Email [email protected]
* Time 2016/11/4
* Function 测试校验版本
* http://bobo.yimwing.com/api/version/android_new
*/
public class CheckVersionActivity extends AppCompatActivity {
private TextView resultTv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check_version);
resultTv = (TextView) findViewById(R.id.tv_result);
}
//开始请求
public void start(View view) {
Call<ResBaseModel<VersionModel>> call = ComApi.getInstance().checkVersion();
call.enqueue(new Callback<ResBaseModel<VersionModel>>() {//异步请求
@Override
public void onResponse(Call<ResBaseModel<VersionModel>> call, final Response<ResBaseModel<VersionModel>> response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (response.isSuccessful() && response.body().isSuccess()) {
resultTv.setText(response.body().getData().getUpdateContent());
} else {
resultTv.setText("失败");
}
}
});
}
@Override
public void onFailure(Call<ResBaseModel<VersionModel>> call, final Throwable t) {
runOnUiThread(new Runnable() {
@Override
public void run() {
resultTv.setText(t.getMessage());
}
});
}
});
}
}
开始运行吧
成功了。
RxJava2使用
这里直接就给大家几篇文章,挺不错的,毕竟我也看了,哈哈。
http://gank.io/post/560e15be2dca930e00da1083
http://www.dieyidezui.com/qian-tan-rxjavayu-2-0de-xin-te-xing/
我也写了几个例子,也给大家看看哈
//Rxjava1.x
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("凌晨");
e.onNext("是");
e.onNext("大佬");
e.onError(new Throwable("给大佬低头"));
}
}).onErrorResumeNext(Observable.<String>empty()).subscribe();
//Rxjava2.x
Flowable.create(new FlowableOnSubscribe<String>() {
@Override
public void subscribe(FlowableEmitter<String> e) throws Exception {
e.onNext("凌晨");
e.onNext("是");
e.onNext("大佬");
e.onError(new Throwable("给大佬低头"));
}
}, BackpressureStrategy.BUFFER).doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.e(TAG, "accept() called with: s = [" + s + "]");
}
}).doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.e(TAG, "accept() called with: throwable = [" + throwable.getMessage() + "]");
}
}).onErrorResumeNext(Flowable.<String>empty()).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.e(TAG, "accept() called with: s = [" + s + "]");
}
});
Flowable.just(R.mipmap.ic_launcher)
.map(new Function<Integer, Bitmap>() {
@Override
public Bitmap apply(Integer integer) throws Exception {
return BitmapFactory.decodeResource(getResources(), integer);
}
}).filter(new Predicate<Bitmap>() {
@Override
public boolean test(Bitmap bitmap) throws Exception {
return bitmap != null;
}
}).doOnNext(new Consumer<Bitmap>() {
@Override
public void accept(Bitmap bitmap) throws Exception {
Log.e(TAG, "accept() called with: bitmap = [" + bitmap.getWidth() + "]");
}
}).onErrorResumeNext(Flowable.<Bitmap>empty())
.subscribe();
哈哈,就是今天自己去看了下,结合官方wiki,写了2个例子,变化还是蛮大的,好了,大家自己看吧。
Retrofit2+Rxjava2
我直接上个代码了
//开始请求
public void start(View view) {
Flowable.create(new FlowableOnSubscribe<ResBaseModel<VersionModel>>() {
@Override
public void subscribe(final FlowableEmitter<ResBaseModel<VersionModel>> e) throws Exception {
Call<ResBaseModel<VersionModel>> call = ComApi.getInstance().checkVersionCall();
call.enqueue(new Callback<ResBaseModel<VersionModel>>() {//异步请求
@Override
public void onResponse(Call<ResBaseModel<VersionModel>> call, final Response<ResBaseModel<VersionModel>> response) {
if (!e.isCancelled()) {
e.onNext(response.body());
}
call.cancel();
e.onComplete();
}
@Override
public void onFailure(Call<ResBaseModel<VersionModel>> call, final Throwable t) {
if (!e.isCancelled()) {
e.onError(t);
}
call.cancel();
e.onComplete();
}
});
}
}, BackpressureStrategy.BUFFER)
.doOnNext(new Consumer<ResBaseModel<VersionModel>>() {
@Override
public void accept(ResBaseModel<VersionModel> versionModelResBaseModel) throws Exception {
if (versionModelResBaseModel.isSuccess()) {
resultTv.setText(versionModelResBaseModel.getData().getUpdateContent());
} else {
resultTv.setText("请求失败");
}
}
}).subscribeOn(new IoScheduler())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
resultTv.setText(throwable.getMessage());
}
})
.onErrorResumeNext(Flowable.<ResBaseModel<VersionModel>>empty())
.subscribe();
}
好了,想必大家肯定看的很丑,其实也没办法,为啥呢?因为Rxjava2还没出来retrofit-adapter,大家敬请期待吧。我自己封装了下,给大家看下。
package com.lingchen.netretrofit.net;
import android.support.annotation.NonNull;
import org.reactivestreams.Publisher;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.FlowableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.internal.schedulers.IoScheduler;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author lingchen
* Email [email protected]
* Time 2016/11/4
* Function 通用接口基类
* 封装线程调度
*/
public class BaseComApi {
/**
* 自己封装的方法,来减少代码亮
*
* @param call retrofit的call
* @param <T> 泛型
* @return Flowable
*/
public static <T> Flowable<T> create(@NonNull final Call<T> call) {
return Flowable.create(new FlowableOnSubscribe<T>() {
@Override
public void subscribe(final FlowableEmitter<T> e) throws Exception {
call.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
e.onNext(response.body());
e.onComplete();
call.cancel();
}
@Override
public void onFailure(Call<T> call, Throwable t) {
e.onError(t);
e.onComplete();
call.cancel();
}
});
}
}, BackpressureStrategy.BUFFER);
}
/**
* 后台线程执行同步,主线程执行异步操作
* 并且拦截所有错误,不让app崩溃
*
* @param <T> 数据类型
* @return Transformer
*/
public static <T> FlowableTransformer<T, T> background() {
return new FlowableTransformer<T, T>() {
@Override
public Publisher<T> apply(Flowable<T> upstream) {
return upstream.subscribeOn(new IoScheduler())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(Flowable.<T>empty());
}
};
}
}
那我们再来看看我们的代码调用
/**
* 检测版本
*/
public Flowable<ResBaseModel<VersionModel>> checkVersion() {
return create(mComInterface.checkVersion())
.compose(BaseComApi.<ResBaseModel<VersionModel>>background());
}
//开始请求
public void start(View view) {
ComApi.getInstance().checkVersion()
.doOnNext(new Consumer<ResBaseModel<VersionModel>>() {
@Override
public void accept(ResBaseModel<VersionModel> versionModelResBaseModel) throws Exception {
if (versionModelResBaseModel.isSuccess()) {
resultTv.setText(versionModelResBaseModel.getData().getUpdateContent());
} else {
resultTv.setText("请求失败");
}
}
})
.doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
resultTv.setText(throwable.getMessage());
}
})
.subscribe();
}
是不是代码少了好多?嘻嘻,如果使用lambda表达式,更简介(好希望squareup公司赶紧出retrofit2支持Rxjava2的adapter)
网络生命周期管理
这个是老生长叹的问题了,用过rxjava1.x都知道调用subscribe之后会返回Subscription,然后利用
CompositeSubscription进行统一管理
//防止RX 导致的内存泄漏
protected CompositeSubscription subscription = new CompositeSubscription();
//添加订阅 由 subscription 管理
protected void add(Subscription sub) {
if (this.subscription != null && sub != null) {
this.subscription.add(sub);
}
}
//移除订阅,并且取消订阅
protected void remove(Subscription sub) {
if (this.subscription != null && sub != null) {
this.subscription.remove(sub);
}
}
//移除所有订阅,并且取消订阅
protected void remove() {
if (this.subscription != null && !this.subscription.isUnsubscribed()) {
this.subscription.unsubscribe();
}
}
那到了Rxjava2.0又怎么管理呢?我们还是看下我们调用subscribe之后返回的是什么吧
@BackpressureSupport(BackpressureKind.UNBOUNDED_IN)
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe() {
return subscribe(Functions.emptyConsumer(), Functions.ERROR_CONSUMER,
Functions.EMPTY_ACTION, FlowableInternalHelper.RequestMax.INSTANCE);
}
/**
* Represents a disposable resource.
*/
public interface Disposable {
/**
* Dispose the resource, the operation should be idempotent.
* 处理资源
*/
void dispose();
/**
* Returns true if this resource has been disposed.
* @return true if this resource has been disposed
* 是否处理资源
*/
boolean isDisposed();
}
/**
* Common interface to add and remove disposables from a container.
* @since 2.0
*/
public interface DisposableContainer {
/**
* Adds a disposable to this container or disposes it if the
* container has been disposed.
* @param d the disposable to add, not null
* @return true if successful, false if this container has been disposed
*/
boolean add(Disposable d);
/**
* Removes and disposes the given disposable if it is part of this
* container.
* @param d the disposable to remove and dispose, not null
* @return true if the operation was successful
*/
boolean remove(Disposable d);
/**
* Removes (but does not dispose) the given disposable if it is part of this
* container.
* @param d the disposable to remove, not null
* @return true if the operation was successful
*/
boolean delete(Disposable d);
}
看到这里,是不是都晓得了?对了DisposableContainer 是一个接口,那我们看看他们的子类
/**
* A disposable container that can hold onto multiple other disposables.
*/
public final class ListCompositeDisposable implements Disposable, DisposableContainer {
List<Disposable> resources;
volatile boolean disposed;
public ListCompositeDisposable() {
}
***
}
/**
* A disposable container that can hold onto multiple other disposables and
* offers O(1) add and removal complexity.
*/
public final class CompositeDisposable implements Disposable, DisposableContainer {
OpenHashSet<Disposable> resources;
volatile boolean disposed;
/**
* Creates an empty CompositeDisposable.
*/
public CompositeDisposable() {
}
***
}
我贴出了关键的代码,2个子类使用了不同的数据结构存储,利弊,大家自己选择吧。
好了我们写个BaseActivity,这里我使用ListCompositeDisposable
/**
* Author lingchen
* Email [email protected]
* Time 2016/11/4
* Function 所有界面基类
*/
public class BaseActivity extends AppCompatActivity {
private ListCompositeDisposable listCompositeDisposable = new ListCompositeDisposable();
protected void addDisposable(Disposable disposable) {
if (disposable != null && !disposable.isDisposed()) {
listCompositeDisposable.add(disposable);
}
}
protected void reDisposable(Disposable disposable) {
if (disposable != null) {
listCompositeDisposable.remove(disposable);
}
}
protected void clear() {
if (!listCompositeDisposable.isDisposed()) {
listCompositeDisposable.clear();
}
}
@Override
protected void onDestroy() {
clear();
super.onDestroy();
}
}
我们修改下刚才的请求
//开始请求
public void start(View view) {
//交给父类管理生命周期
addDisposable(ComApi.getInstance().checkVersion()
.doOnNext(new Consumer<ResBaseModel<VersionModel>>() {
@Override
public void accept(ResBaseModel<VersionModel> versionModelResBaseModel) throws Exception {
if (versionModelResBaseModel.isSuccess()) {
resultTv.setText(versionModelResBaseModel.getData().getUpdateContent());
} else {
resultTv.setText("请求失败");
}
}
})
.doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
resultTv.setText(throwable.getMessage());
}
})
.subscribe());
}
我擦,差点忘记重点,在封装call转成Flowable的时候没有加上判断,上代码,你们能看懂的
Log.e(TAG, "onResponse: ");
if (!e.isCancelled()) {
Log.e(TAG, "onResponse: no cancel");
e.onNext(response.body());
e.onComplete();
}
call.cancel();
onFailure我就不放了 一样的,那好,我们现在写个测试一下,我们在开启请求的时候写一个延迟调用父类的clear,代码如下
//开始请求
public void start(View view) {
//交给父类管理生命周期
addDisposable(ComApi.getInstance().checkVersion()
.doOnNext(new Consumer<ResBaseModel<VersionModel>>() {
@Override
public void accept(ResBaseModel<VersionModel> versionModelResBaseModel) throws Exception {
if (versionModelResBaseModel.isSuccess()) {
resultTv.setText(versionModelResBaseModel.getData().getUpdateContent());
} else {
resultTv.setText("请求失败");
}
}
})
.doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
resultTv.setText(throwable.getMessage());
}
})
.subscribe());
//延迟0.1s取消
resultTv.postDelayed(new Runnable() {
@Override
public void run() {
clear();
}
}, 100);
}
好,我们运行下(这里就不妨图片了,因为大家都在吐槽图片看不清,而且不能放大)
11-04 18:22:45.304 21372-21372/com.lingchen.netretrofit E/BaseComApi: onResponse:
大家看到了只有onResponse回调,那么意思走到 if (!e.isCancelled()),我们取消了,所以没有打印onResponse: no cancel,
我们现在把延迟去掉或者延迟时间长一点,在运行下
11-04 18:26:35.631 24805-24805/com.lingchen.netretrofit E/BaseComApi: onResponse:
11-04 18:26:35.631 24805-24805/com.lingchen.netretrofit E/BaseComApi: onResponse: no cancel
哈哈,大家看懂了吧
到这里大家可能会问,那我重复点击发送,是什么样子呢?我们运行下
11-04 18:26:55.354 24805-24805/com.lingchen.netretrofit E/BaseComApi: onResponse:
11-04 18:26:55.355 24805-24805/com.lingchen.netretrofit E/BaseComApi: onResponse: no cancel
11-04 18:26:55.472 24805-24805/com.lingchen.netretrofit E/BaseComApi: onResponse:
11-04 18:26:55.472 24805-24805/com.lingchen.netretrofit E/BaseComApi: onResponse: no cancel
可以发现,确实回来了2次,那我们现在想做的是,如果多次点击,那就取消前面发送的,这个东西呢我们只能自己去封装,去实现DisposableContainer 这个接口,大体的意思可以为发送请求加一个Tag标识符,每当我们add(Disposable )时候,我们就看看我们存储的Disposable有没有标识符是Tag的,如果有,那就直接取消吧,嗯,大体就是这个样子。
结束语
好了,搞腾了一天了,终于搞定了。感谢大家对我前2个博客的支持,谢谢大家。
Rxjava2.0刚出来,以后我会出个针对Rxjava2.0的文章。
下篇文章可能会出retrofit相关的(上传/下载图片或者文件等)!!!
拜拜喽(今天周五了哈)!!!!下面给出源码
感谢&完善
感谢"yuke"对我这次封装的提的意见(以前公司的同事),我们来看看原来封装的代码:
/**
* 自己封装的方法,来减少代码亮
*
* @param call retrofit的call
* @param <T> 泛型
* @return Flowable
*/
public static <T> Flowable<T> create(@NonNull final Call<T> call) {
return Flowable.create(new FlowableOnSubscribe<T>() {
@Override
public void subscribe(final FlowableEmitter<T> e) throws Exception {
call.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
Log.e(TAG, "onResponse: ");
if (!e.isCancelled()) {
Log.e(TAG, "onResponse: no cancel");
e.onNext(response.body());
e.onComplete();
}
}
@Override
public void onFailure(Call<T> call, Throwable t) {
Log.e(TAG, "onFailure() called with: , t = [" + t + "]");
if (!e.isCancelled()) {
Log.e(TAG, "onResponse: no cancel");
e.onError(t);
e.onComplete();
}
}
});
}
}, BackpressureStrategy.BUFFER);
}
第一个问题:我们这里使用的是 call.enqueue,这是异步的调用方法,很明显就没有跟Rxjava线程管理搭上边,所以我们修正下(只是把异步执行转成同步,把线程分配交给Rxjava)。
第二个问题:这个也不是问题吧,是个改善。大家可以看看上面的代码,我们不管你取消不取消当前的网络请求,我们都会去请求网络,只是在回调的时候我们再去判断是否取消了订阅。我们下面假设下面2种情况
1.网络请求还没发送,我们就取消订阅了。(其实这种情况是不可能发生的,除非你在发送请求的线程做个sleep。这种情况我们就不考虑了,因为是我们自己封装的,也不会在发送请求之前还延迟,所以就不考虑这种情况了)。
2.网络请求发送了,还没有回调,我们现在取消订阅。我们手动调用call.cancel();就会触发onFailure,异常是sokcet closed(异步,同步是 thread interrupted),那就跟我们以前的做法一样,都是在网络回调做处理,但是,如果我在取消订阅的时候,立马执行call.cancel(),带来的好处就是,会立马触发onFailure,不用等待网络请求回调了(毕竟都不知道会什么时候回调),所以这就体现我手动调用call.cancel()的好处。那好,我们现在上最终的代码:
/**
* 自己封装的方法,来减少代码亮
*
* @param call retrofit的call
* @param <T> 泛型
* @return Flowable
*/
public static <T> Flowable<T> create(@NonNull final Call<T> call) {
return Flowable.create(new FlowableOnSubscribe<T>() {
@Override
public void subscribe(final FlowableEmitter<T> e) throws Exception {
//设置取消监听
e.setCancellable(new Cancellable() {
@Override
public void cancel() throws Exception {
Log.e(TAG, "cancel: ");
if (!call.isCanceled()) {
call.cancel();
}
}
});
//同步执行请求,把线程管理交给Rx
try {
Response<T> response = call.execute();
Log.e(TAG, "onResponse: ");
if (!e.isCancelled()) {
e.onNext(response.body());
e.onComplete();
}
} catch (Exception exception) {
Log.e(TAG, "exception with: exception = [" + exception.getMessage() + "]");
if (!e.isCancelled()) {
Log.e(TAG, "onResponse: no cancel");
e.onError(exception);
e.onComplete();
}
}
}
}, BackpressureStrategy.BUFFER);
}
好了,这里再次感谢"yuke",也希望大家多多提提意见,一起成长!!!代码已经同步到github。
拜拜!!!