IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> RxJava + Retrofit + MVP(看完还不明白,android面试题2018 -> 正文阅读

[移动开发]RxJava + Retrofit + MVP(看完还不明白,android面试题2018

}
}
}
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);

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-24 11:01:03  更:2022-01-24 11:03:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 13:04:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码