一步步搭建Retrofit+RxJava+MVP网络请求框架(一)
首先,展示一下封装好之后的项目的层级结构。
1、先创建一个RetrofitApiService.java
package com.xdw.retrofitrxmvpdemo.http; import com.xdw.retrofitrxmvpdemo.model.UserInfo; import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable; /**
* Created by 夏德旺 on 2017/12/8.
*/ public interface RetrofitApiService { @GET("userinfo")
Observable<UserInfo> getUserInfo(@Query("uid") int uid); }
这里就是把原生的retrofit中的Call换成了RxJava中的Observable。
2、封装RetrofitUtil
package com.xdw.retrofitrxmvpdemo.http; import android.content.Context; import com.google.gson.GsonBuilder;
import com.xdw.retrofitrxmvpdemo.constant.UrlConstant; import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory; /**
* Created by 夏德旺 on 2017/12/8.
*/ public class RetrofitUtil {
private Context mCntext;
//声明Retrofit对象
private Retrofit mRetrofit;
//声明RetrofitApiService对象
private RetrofitApiService retrofitApiService;
OkHttpClient client = new OkHttpClient();
GsonConverterFactory factory = GsonConverterFactory.create(new GsonBuilder().create()); //由于该对象会被频繁调用,采用单例模式,下面是一种线程安全模式的单例写法
private volatile static RetrofitUtil instance; public static RetrofitUtil getInstance(Context context){
if (instance == null) {
synchronized (RetrofitUtil.class) {
if (instance == null) {
instance = new RetrofitUtil(context);
}
}
}
return instance;
}
private RetrofitUtil(Context mContext){
mCntext = mContext;
init();
} //初始化Retrofit
private void init() {
mRetrofit = new Retrofit.Builder()
.baseUrl(UrlConstant.BASE_URL)
.client(client)
.addConverterFactory(factory)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
retrofitApiService = mRetrofit.create(RetrofitApiService.class);
} public RetrofitApiService getRetrofitApiService(){
return retrofitApiService;
}
}
3、封装DataManager,这里和原生的retrofit的封装一样该类用来管理RetrofitApiService中对应的各种API接口,当做Retrofit和presenter中的桥梁,Activity就不用直接和retrofit打交道了
package com.xdw.retrofitrxmvpdemo.manager; import android.content.Context; import com.xdw.retrofitrxmvpdemo.http.RetrofitApiService;
import com.xdw.retrofitrxmvpdemo.http.RetrofitUtil;
import com.xdw.retrofitrxmvpdemo.model.UserInfo; import rx.Observable; /**
* Created by 夏德旺 on 2017/12/8.
*/ //该类用来管理RetrofitApiService中对应的各种API接口,
// 当做Retrofit和presenter中的桥梁,Activity就不用直接和retrofit打交道了
public class DataManager {
private RetrofitApiService mRetrofitService;
private volatile static DataManager instance; private DataManager(Context context){
this.mRetrofitService = RetrofitUtil.getInstance(context).getRetrofitApiService();
}
//由于该对象会被频繁调用,采用单例模式,下面是一种线程安全模式的单例写法
public static DataManager getInstance(Context context) {
if (instance == null) {
synchronized (DataManager.class) {
if (instance == null) {
instance = new DataManager(context);
}
}
}
return instance;
} //将retrofit的业务方法映射到DataManager中,以后统一用该类来调用业务方法
//以后再retrofit中增加业务方法的时候,相应的这里也要添加,比如添加一个getOrder
public Observable<UserInfo> getUserInfo(int uid){
return mRetrofitService.getUserInfo(uid);
}
}
4、创建一个Presenter接口,这里就引入了Presenter这个东西了,后面我们根据具体的业务创建对应的实例去实现该接口。该接口主要面向数据,后面还会创建一个PresentView接口(面向View的),然后通过
BindPresentView方法将这2个接口关联起来,从而实现对数据和Activity的管理。
package com.xdw.retrofitrxmvpdemo.presenter; import com.xdw.retrofitrxmvpdemo.pv.PresentView; /**
* Created by 夏德旺 on 2017/12/8.
*/ public interface Presenter {
//Presenter初始化
void onCreate();
//销毁
void onDestroy();
//绑定视图
void BindPresentView(PresentView presentView);
}
5、定义一个实现Presenter的基础类BasePresenter,后续具体功能类继承于它,主要是为了在该类中写一些共用方法,比如
CompositeSubscription的创建与销毁。(CompositeSubscription干嘛用的可以查阅RxJava的资料)
package com.xdw.retrofitrxmvpdemo.presenter; import com.xdw.retrofitrxmvpdemo.pv.PresentView; import rx.subscriptions.CompositeSubscription; /**
* Created by 夏德旺 on 2017/12/8.
*/
//定义一个Presenter的基础类,后续具体功能类继承于它
public class BasePresenter implements Presenter {
//声明一个CompositeSubscription对象,注意是protected修饰符,便于子类进行调用
protected CompositeSubscription mCompositeSubscription;
@Override
public void onCreate() {
//在基础类中对CompositeSubscription进行初始化,子类中就不用再写一次
//子类如果需要对onCreate进行重写,记得先调用super.onCreate();
mCompositeSubscription = new CompositeSubscription();
} @Override
public void onDestroy() {
//释放CompositeSubscription,否则会造成内存泄漏
if (mCompositeSubscription.hasSubscriptions()){
mCompositeSubscription.unsubscribe();
}
} @Override
public void BindPresentView(PresentView presentView) {
//与具体视图进行绑定,留个子类进行扩展
}
}
6、创建一个接口PresentView,面向视图View的接口,和前面的Prenseter配合使用
package com.xdw.retrofitrxmvpdemo.pv; /**
* Created by 夏德旺 on 2017/12/8.
*/ //面向视图View的接口,和前面的Prenseter配合使用
public interface PresentView {
//定义一个最基础的接口,里面就包含一个出错信息的回调
//因为大多数时候报错的时候都是采用一条信息提示
//如果需要负责的报错接口,请重载onError,是重载不是重写
void onError(String result);
}
7、之前还已经创建了2个类,这里补充下,一个是UrlConstant(用来存放常量的,这里用来存放Base Url),另外一个是数据模型类UserInfo
UrlConstant.java:
package com.xdw.retrofitrxmvpdemo.constant; /**
* Created by 夏德旺 on 2017/12/8.
*/ public class UrlConstant {
/**
* 域名:
* 调试:http://10.1.1.192
*/
public static final String BASE_URL="http://10.1.1.192";
}
UserInfo.java:
package com.xdw.retrofitrxmvpdemo.model; /**
* Created by 夏德旺 on 2017/12/8.
*/ public class UserInfo {
private String username;
private int age; public UserInfo(String username, int age) {
this.username = username;
this.age = age;
} public String getUsername() {
return username;
} public int getAge() {
return age;
} @Override
public String toString() {
return "UserInfo{" +
"username='" + username + '\'' +
", age=" + age +
'}';
}
}
8、下面就需要将具体的业务加入到Presenter中了,先写一个UserInfoPv继承自PresentView接口,这个是根据具体业务添加。
package com.xdw.retrofitrxmvpdemo.pv; import com.xdw.retrofitrxmvpdemo.model.UserInfo; /**
* Created by 夏德旺 on 2017/12/8.
*/ public interface UserInfoPv extends PresentView {
//对基础接口PresentView进行扩展,添加onSuccess回调
//因为该回调与具体的业务对应,所以不能写到基础接口里面
//比如UserInfo的回调就创建一个UserInfoPv的接口,如果新增一个Order的业务,
//则新增一个OrderPv的接口
void onSuccess(UserInfo userInfo);
}
9、写一个UserInfoPresenter继承BasePresenter类,在该类中实现数据的请求,并且将该类与业务对应的PresentView进行绑定,这里是和UserInfoPv绑定
package com.xdw.retrofitrxmvpdemo.presenter; import android.content.Context; import com.xdw.retrofitrxmvpdemo.manager.DataManager;
import com.xdw.retrofitrxmvpdemo.model.UserInfo;
import com.xdw.retrofitrxmvpdemo.pv.PresentView;
import com.xdw.retrofitrxmvpdemo.pv.UserInfoPv; import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; /**
* Created by 夏德旺 on 2017/12/8.
*/ //该类是具体业务presenter,如需增加另一个业务,比如Order
//则可以再创建一个OrderPresenter
public class UserInfoPresenter extends BasePresenter {
private Context mContext;
private UserInfoPv mUserInfoPv;
private UserInfo mUserInfo;
public UserInfoPresenter (Context context){
this.mContext = context;
} @Override
public void BindPresentView(PresentView presentView) {
mUserInfoPv = (UserInfoPv)presentView;
} //在presenter中实现业务逻辑,此处会调用前面封装好的retrofit的东西
//将处理结果绑定到对应的PresentView实例,这样Activity和PresentView实例绑定好之后,
//Activity->PresentView->Presenter->retrofit的关系就打通了
public void getUserInfo(int uid){
super.mCompositeSubscription.add(DataManager.getInstance(mContext).getUserInfo(uid)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UserInfo>() {
@Override
public void onCompleted() {
if (mUserInfo != null){
mUserInfoPv.onSuccess(mUserInfo);
}
} @Override
public void onError(Throwable e) {
e.printStackTrace();
mUserInfoPv.onError("请求失败!!");
} @Override
public void onNext(UserInfo userInfo) {
mUserInfo = userInfo;
}
})
);
}
}
10、好了,retrofit与rxjava,presenter相关的东西都封装好了,接下来轮到之前苦逼的Activity出场了,在Activity中展示presenter传递过来的数据。
package com.xdw.retrofitrxmvpdemo.activity; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast; import com.xdw.retrofitrxmvpdemo.R;
import com.xdw.retrofitrxmvpdemo.model.UserInfo;
import com.xdw.retrofitrxmvpdemo.presenter.UserInfoPresenter;
import com.xdw.retrofitrxmvpdemo.pv.UserInfoPv; public class MainActivity extends AppCompatActivity {
private TextView text;
private Button button;
//定义需要调用的presenter对象
private UserInfoPresenter mUserInfoPresenter =new UserInfoPresenter(this); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView)findViewById(R.id.text);
button = (Button)findViewById(R.id.button);
//在Activity创建的时候同时初始化presenter,这里onCreater不是指的创建presenter对象,
// 而是做一些presenter的初始化操作,名字应该取名init更好理解点,我这里就不重命名了
mUserInfoPresenter.onCreate();
//将presenter和PresentView进行绑定,实际上就是将presenter和Activity视图绑定,
//这个是MVP模式中V与P交互的关键
mUserInfoPresenter.BindPresentView(mUserInfoPv);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击按钮触发presenter里面的方法
mUserInfoPresenter.getUserInfo(1);
}
}); } //采用内部类方法定义presentView对象,该对象用来将Activity和presenter进行绑定
//绑定了以后主线程中就可以通过回调来获取网络请求的数据
private UserInfoPv mUserInfoPv = new UserInfoPv(){
@Override
public void onSuccess(UserInfo userInfo) {
text.setText(userInfo.toString());
} @Override
public void onError(String result) {
Toast.makeText(MainActivity.this,result, Toast.LENGTH_SHORT).show();
}
}; //在Activity销毁的时候,一定要对CompositeSubscription进行释放,否则会造成内存泄漏
//释放操作封装到了presenter的ondestroy方法中
@Override
protected void onDestroy(){
super.onDestroy();
mUserInfoPresenter.onDestroy();
}
}
补充下:截图中的Result这个类是我实际项目中用到的,这里简化了下业务逻辑,就没用到它。
Result.java:
package com.xdw.retrofitrxmvpdemo.model; /**
* Created by 夏德旺 on 2017/12/8.
*/ public class Result<T> {
private int code;
private String msg;
private T data; public Result(int code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
} public int getCode() {
return code;
} public String getMsg() {
return msg;
} public T getData() {
return data;
} @Override
public String toString() {
return "Result{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
最后说明下,可能有的人觉得本来之前直接在Activity中写retrofit很方便,现在却加了这么多代码,视乎变得更麻烦了。但是自己仔细想想设计模式,当业务变得越来越复杂的时候,这种封装就会变得越来越有意义。
列举下之后像该项目中扩展业务的步骤,比如加一个订单功能。
操作步骤:
1、添加对应的model类Order
2、RetrofitApiService中添加对应的网络请求api
3、将新添加的api映射到DataManager中
4、添加业务对应的PrensentView实例OrderPv
5、添加业务对应的Presenter实例OrderPresenter
6、在需要该业务的UI线程(Activity或Fragment)中调用具体业务对应的Presenter
看着新添加一个业务的过程是不是很多?但是逻辑很清晰,扩展很容易,写代码不是说代码量越少,代表代码写的越好越有效率。
之后还会对该框架进一步封装,加入拦截器,网络请求等待框等功能的封装。
补充下我这里测试用的服务端源码,就一个index.php文件:
<?php
header("Content-Type: application/json; charset=utf-8");
$uid=$_GET['uid'];
if($uid==1){
$arr['code']=200;
$arr['msg']='ok';
$data['username']='xiadewang';
$data['age']=30;
$arr['userinfo']=$data;
echo json_encode($data,JSON_UNESCAPED_UNICODE);
}
android代码链接:http://download.csdn.net/download/aaaabbbb1019/10151399
一步步搭建Retrofit+RxJava+MVP网络请求框架(一)的更多相关文章
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了
在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...
- android开发学习 ------- Retrofit+Rxjava+MVP网络请求的实例
http://www.jianshu.com/p/7b839b7c5884 推荐 ,照着这个敲完 , 测试成功 , 推荐大家都去看一下 . 下面贴一下我照着这个敲完的代码: Book实体类 - 用 ...
- kotlin for android----------MVP模式下(OKHttp和 Retrofit+RxJava)网络请求的两种实现方式
今天要说的干货是:以Kotlin,在MVP模式下(OKHttp和 Retrofit+RxJava)网络请求两种实现方式的一个小案例,希望对大家有所帮助,效果图: Retrofit是Square公司开发 ...
- 基于Retrofit+RxJava的Android分层网络请求框架
目前已经有不少Android客户端在使用Retrofit+RxJava实现网络请求了,相比于xUtils,Volley等网络访问框架,其具有网络访问效率高(基于OkHttp).内存占用少.代码量小以及 ...
- Android 网络请求框架Retrofit
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp ...
- 安卓开发常用网络请求框架OkHttp、Volley、XUtils、Retrofit对比
网络请求框架总结1.xutils 此框架庞大而周全,这个框架可以网络请求,同时可以图片加载,又可以数据存储,又可以 View 注解,使用这种框架很方便,这样会使得你整个项目对它依赖性太强,万一 ...
- 【转载】一步一步搭建自己的iOS网络请求库
一步一步搭建自己的iOS网络请求库(一) 大家好,我是LastDay,很久没有写博客了,这周会分享一个的HTTP请求库的编写经验. 简单的介绍 介绍一下,NSURLSession是iOS7中新的网络接 ...
- App 组件化/模块化之路——如何封装网络请求框架
App 组件化/模块化之路——如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...
- Android网络请求框架
本篇主要介绍一下Android中经常用到的网络请求框架: 客户端网络请求,就是客户端发起网络请求,经过网络框架的特殊处理,让后将请求发送的服务器,服务器根据 请求的参数,返回客户端需要的数据,经过网络 ...
随机推荐
- LeetCode 661. Image Smoother (图像平滑器)
Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoother t ...
- Jenkins集成taffy进行自动化测试并输出测试报告
本文主要介绍Jenkins集成taffy/nose框架进行自动化测试并输出测试报告方法. 0. 测试环境 Jenkis主节点部署在CentOS系统上,子节点为Win10 64位系统(即我们本机运行自动 ...
- js判断是否使用的是微信浏览器
代码如下: function is_weixin() { var ua = navigator.userAgent.toLowerCase(); return ua.match(/MicroMesse ...
- Oracle 表空间扩充
Oracle 表空间扩充 一.现场环境: (1)操作系统:AIX (2)数据库:Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - ...
- hdu1285 确定比赛名次(拓扑排序)
有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道 ...
- Ellipse
Description There is an beautiful ellipse whose curve equation is: b > 0)" src="http:// ...
- 【转载】XSS学习笔记
XSS的分类 非持久型 非持久型XSS也称反射型XSS.具体原理就是当用户提交一段代码的时候,服务端会马上返回页面的执行结果.那么当攻击者让被攻击者提交一个伪装好的带有恶意代码的链接时,服务端也会立刻 ...
- SElinux用户管理操作
查看当前用户上下文 id -Z 查看登陆的用户和其对应的SELinux用户 semanage login -l 改变用户和SELinux的对应关系 semanage login -a选项能改变,-s用 ...
- Python函数篇:装饰器
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理. ...
- SVN服务迁移备份操作步骤
SVN服务备份操作步骤 1.准备源服务器和目标服务器 源服务器:192.168.1.250 目标服务器:192.168.1.251 root/rootroot 2.对目标服务器(251)装SVN服务器 ...