} } } return retrofitManager; }
private void initRetrofit() { retrofit = new Retrofit.Builder() .baseUrl(SystemConst.DEFAULT_SERVER) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClient) .build(); retrofitApiService = retrofit.create(RetrofitApiService.class); }
public static RetrofitApiService getApiService() { return retrofitManager.retrofitApiService; }
private void initOkHttpClient() { okHttpClient = new OkHttpClient.Builder() //设置缓存文件路径,和文件大小 .cache(new Cache(new File(Environment.getExternalStorageDirectory() + “/okhttp_cache/”), 50 * 1024 * 1024)) .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .addInterceptor(new HttpLogInterceptor()) //设置在线和离线缓存 .addInterceptor(OfflineCacheInterceptor.getInstance()) .addNetworkInterceptor(NetCacheInterceptor.getInstance()) .build(); } }
5.2、比如我们来写GetFragment这块。首先写契约类
回想之前我们有个BaseView。里面有2个方法showLoading和hideLoading (只要记住大家通用的方法封装成base,有些页面不同就不调用就行了) 代码如下:
public interface BaseView {
//显示正在加载loading void showLoading(String message);
// 关闭正在加载loading void hideLoading();
//防止RxJava内存泄漏,可以暂且忽略 LifecycleTransformer bindLifecycle();
}
那么GetFragment契约类就是(还要说下这里的presenter接口只是GetPresenter所要用的方法,放在契约类里,一目了然):
public interface GetContract {
//view只有2个更新ui的方法 interface View extends BaseView { // 1、获取get数据,更新ui void showGetData(String data);
// 2、获取get数据失败,更新ui void showGetError(String msg); }
//get的prensenter只有一个获取get数据的数据请求 interface Prensenter { // 1、开启get网络请求 public void getGetData(String params); } }
5.3、接下来是GetPresenter的实体类,当然这里有个BasePresenter(以下讲解移除部分代码更清晰)
我们想象有什么通用方法是在BasePresenter里的?当然你可以把一些复杂的写很多步骤的网络请求封装在这里,比如我们项目里的下载文件等,这里我们讲简单的通用方法
GetPresenter需要view的引用 所以有:1、setView加入引用 2、view = null置空引用,防止oom
//这个是为了退出页面,取消请求的 public CompositeDisposable compositeDisposable; // 绑定的view private V mvpView; //绑定view,一般在初始化中调用该方法 public void attachView(V mvpView) { this.mvpView = mvpView; compositeDisposable = new CompositeDisposable(); } //置空view,一般在onDestroy中调用 public void detachView() { this.mvpView = null; //退出页面的时候移除所有网络请求 removeDisposable(); } //需要退出页面移除网络请求的加入进来 public void addDisposable(Disposable disposable) { compositeDisposable.add(disposable); } //退出页面移除所有网络请求 public void removeDisposable() { if (compositeDisposable != null) { compositeDisposable.dispose(); } }
使用一个方法快速获取RetrofitManager里的网络配置
public RetrofitApiService apiService() { return RetrofitManager.getRetrofitManager().getApiService(); }
大部分的网络请求都有showLoading和hideLoading,还有线程切换,封装进来
//这里我多加了个是否显示loading的标识和loading上的文字,想偷懒可以用方法重载把这2个参数默认 public Observable observe(Observable observable, final boolean showDialog, final String message) { return observable.subscribeOn(Schedulers.io()) .doOnSubscribe(new Consumer() { @Override public void accept(Disposable disposable) throws Exception { if (showDialog) { mvpView.showLoading(message); } } }) .subscribeOn(AndroidSchedulers.mainThread()) .doFinally(new Action() { @Override public void run() throws Exception { if (showDialog) { mvpView.hideLoading(); } } }) .observeOn(AndroidSchedulers.mainThread()) //防止RxJava内存泄漏 .compose(mvpView.bindLifecycle()); }
那么我们的BasePresenter(移除部分代码更清晰)
//这里加上泛型,第一在使用Presenter一眼就看出对应哪个View,其次确定我们V的类型 public abstract class BasePresenter { public CompositeDisposable compositeDisposable;
private V mvpView;
public void attachView(V mvpVie w) { this.mvpView = mvpView; compositeDisposable = new CompositeDisposable(); } public void detachView() { this.mvpView = null; removeDisposable(); } //检查是否有view的引用 public boolean isViewAttached() { return mvpView != null; }
//获取view的引用 public V getView() { return mvpView; }
public RetrofitApiService apiService() { return RetrofitManager.getRetrofitManager().getApiService(); } //需要退出页面移除网络请求的加入进来 public void addDisposable(Disposable disposable) { }
//退出页面移除所有网络请求 public void removeDisposable() {}
//省的写线程切换和showloading和hide的复杂操作 public Observable observe(Observable observable, final boolean showDialog, final String message) {}
}
那么GetPresenter就是这样
//省略部分代码,便于理解。实体GetPresenter实现GetContract.Prensenter接口,里面就一个getGetData方法 public class GetPresenter extends BasePresenter<GetContract.View> implements GetContract.Prensenter {
@Override public void getGetData(String params) { if (!isViewAttached()) { //如果没有View引用就不加载数据 return; } //BasePresenter里有了封装,切换线程和放置内存泄漏的 .compose(mvpView.bindLifecycle())都不用写了 //代码越能偷懒,说明框架越是封装的完美 observe(apiService().getGank(params)) .subscribe(new Consumer() { @Override public void accept(GankFatherBean gankFatherBean) throws Exception { getView().showGetData(gankFatherBean.getTitle()); } }, new Consumer() { @Override public void accept(Throwable throwable) throws Exception { getView().showGetError(throwable.toString()); } });
} }
5.4、其次是BaseFragment
因为使用RxJava,如果使用不当很容易造成RxJava内存泄漏,所以官方也出了方法继承RxFragment
因为fragment是作为view是要实现view接口的,同时每个fragment都要有presenter去调用方法 初步如下(省了部分代码,便于理解):
public abstract class BaseFragment extends RxFragment implements BaseView { public T mPresenter; public abstract T cretaePresenter(); protected View mContentView; private Unbinder mUnbinder;
@Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // 避免多次从xml中加载布局文件 mPresenter = cretaePresenter(); if (mPresenter != null) { mPresenter.attachView(this); } return mContentView; }
@Override public void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.detachView(); mPresenter = null; } }
@Override public void showLoading(String message) { LoadingDialog.getInstance().show(getActivity(), message); }
@Override public void hideLoading() { LoadingDialog.getInstance().dismiss(); }
//防止Rx内存泄漏 @Override public LifecycleTransformer bindLifecycle() { LifecycleTransformer objectLifecycleTransformer = bindToLifecycle(); return objectLifecycleTransformer; } }
5.5、在GetFragment里使用就是这样(省略部分代码,便于理解)
public class GETFragment extends BaseFragment implements GetContract.View { @BindView(R.id.txt_content) TextView txt_content;
@Override public GetPresenter cretaePresenter() { return new GetPresenter(); }
@Override public int getContentViewId() { return R.layout.fragment_get; }
//处理逻辑 @Override protected void processLogic(Bundle savedInstanceState) {
}
@OnClick(R.id.txt_get) public void getClick() { //请求网络 mPresenter.getGetData(“Android”); }
@Override public void showGetData(String data) { txt_content.setText(data); }
@Override public void showGetError(String msg) { ToastUtils.showToast(msg); } }
6、断网重连
因为使用了强大的RxJava,这里断网重连用的就是操作符retryWhen,封装在BasePresenter里的observeWithRetry。这里就不多讲了,可以先把操作符retryWhen了解清楚就看明白了
7、取消网络请求
这里的返回值就是一个disposable,如果主动取消就直接调 disposable.dispose();当然我这里也封装了离开页面取消请求你可以把它加到addDisposable(Disposable disposable)里。就不用管了
Disposable disposable = observe(apiService().getGank(params)) .subscribe(new Consumer() { @Override public void accept(GankFatherBean gankFatherBean) throws Exception { getView().showGetData(gankFatherBean.getTitle()); } }, new Consumer() { @Override public void accept(Throwable throwable) throws Exception { getView().showGetError(throwable.toString()); } });
8、多次请求同一网络,只请求一次
这里是在RetrofitManage里放了一个private ArrayList oneNetList;请求网络的时候把,方法名当成tag加入进去,如果请求的时候判断下,oneNetList里如果已经有次tag,则直接return,在请求成功或者失败的时候移除tag
9、在线缓存和离线缓存
这里还是利用了okhttp的拦截器,所以这里再次吐槽下Retrofit。
- 离线缓存拦截器 OfflineCacheInterceptor
- 在线缓存拦截器 NetCacheInterceptor
这里不清楚的可以去看我之前的一篇文章EasyOk。讲的很详细,简直就是一模一样 本项目具体用法在,GetPresenter里有。
10、上传文件进度监听
因为用Restrofit上传文件是这样的。
@POST @Multipart Observable uploadPic(@Url String url, @Part MultipartBody.Part file);
参数是MultipartBody.Part。不监听进度参数就是这样写的
RequestBody requestFile = RequestBody.create(MediaType.parse(“multipart/form-data”), file); MultipartBody.Part body = MultipartBody.Part.createFormData(“file”, file.getName(), requestFile);
如果要监听进度,就要重写RequestBody,把文件写入进度返回出来,其实和EasyOk的思路是一模一样的,本项目上传文件相关类在: retrofitwithrxjava.uploadutils的包里。用法在postfragment里。其中包括多张图片监听,不同key,不同图片。和同一key,不同图片
11、下载文件进度监听及断点下载
首先我们看下载文件请求
@GET @Streaming //10以上用@streaming。不会造成oom,反正你用就是了 Observable downloadFile(@Url String url);
t.createFormData(“file”, file.getName(), requestFile);
如果要监听进度,就要重写RequestBody,把文件写入进度返回出来,其实和EasyOk的思路是一模一样的,本项目上传文件相关类在: retrofitwithrxjava.uploadutils的包里。用法在postfragment里。其中包括多张图片监听,不同key,不同图片。和同一key,不同图片
11、下载文件进度监听及断点下载
首先我们看下载文件请求
@GET @Streaming //10以上用@streaming。不会造成oom,反正你用就是了 Observable downloadFile(@Url String url);
|