Retrofit2+Rxjava+MVP实践
此博文根据前面两篇文章 Android MVP 架构初试
Android MVP 架构封装
再结合主流框架Retrofit2+Rxjava
来个实践
源码地址RxMVP
项目截图
Retrofit2+Rxjava 封装
JuHeService 数据请求接口
/**
* 请求示例:
* http://v.juhe.cn/dream/query
* q:梦境关键字,如:黄金 需要utf8 urlencode
* cid:指定分类,默认全部
* full: 是否显示详细信息,1:是 0:否,默认0
*/
public interface JuHeService {
@GET("dream/query")
Observable<HttpJuHeResult<List<JuHeDream>>> getDreams(@QueryMap Map<String, Object> options);
}
HttpJuHeMethods 聚合解梦封装的方法
public class HttpJuHeMethods {
public static final String BASE_URL = "http://v.juhe.cn/";
private static final int DEFAULT_TIMEOUT = 5;
private Retrofit retrofit;
private JuHeService juheService;
//构造方法私有
private HttpJuHeMethods() {
//手动创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).build();
retrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
juheService = retrofit.create(JuHeService.class);
}
//在访问HttpMethods时创建单例
private static class SingletonHolder{
private static final HttpJuHeMethods INSTANCE = new HttpJuHeMethods();
}
//获取单例
public static HttpJuHeMethods getInstance(){
return SingletonHolder.INSTANCE;
}
/**
* 用来统一处理Http的resultCode,并将HttpResult的Data部分剥离出来返回给subscriber
*
* @param <T> Subscriber真正需要的数据类型,也就是Data部分的数据类型
*/
private class HttpResultFunc<T> implements Func1<HttpJuHeResult<T>, T> {
@Override
public T call(HttpJuHeResult<T> httpResult) {
if (httpResult.getError_code() != 0) {
throw new ApiException(httpResult.getError_code());
}
return httpResult.getResult();
}
}
private <T> void toSubscribe(Observable<T> observable, Subscriber<T> subscriber){
observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
/**
* 用于获取聚合笑话的数据
* @param subscriber 由调用者传过来的观察者对象
* @param options 访问参数
*/
public void getJokesByHttpResultMap(Subscriber<List<JuHeDream>> subscriber, Map<String, Object> options){
// juheService.getJokesByRxJavaHttpResult(options)
// .map(new HttpResultFunc<JuHeDream>())
// .subscribeOn(Schedulers.io())
// .unsubscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(subscriber);
Observable<List<JuHeDream>> observable = juheService.getDreams(options)
.map(new HttpResultFunc<List<JuHeDream>>());
toSubscribe(observable,subscriber);
}
}
其中包含异常的处理
public class ApiException extends RuntimeException{
public final static int TIME_MUST_10=209501;
public final static int TIME_OTHER=209502;
public ApiException(int resultCode) {
this(getApiExceptionMessage(resultCode));
}
public ApiException(String detailMessage) {
super(detailMessage);
}
/**
* 由于服务器传递过来的错误信息直接给用户看的话,用户未必能够理解
* 需要根据错误码对错误信息进行一个转换,在显示给用户
* @param code
* @return
*/
private static String getApiExceptionMessage(int code){
String message = "";
switch (code) {
case TIME_MUST_10:
message = "必须为10位时间戳";
break;
case TIME_OTHER:
message = "page、pagesize必须为int类型,time为10位时间戳";
break;
default:
message = "未知错误";
}
return message;
}
}
BaseMvp封装
请参考上篇文章 Android MVP 架构封装
Retrofit2+Rxjava+MVP实践
MvpView
public interface MvpView extends BaseView {
//ListView的初始化
void setListItem(List<JuHeDream> data);
//Toast 消息
void showMessage(String messgae);
}
MvpPresenter
public class MvpPresenter extends BasePresenter<MvpView> {
private Context mContext;
private Subscriber subscriber;
private List<JuHeDream> mDatas;
public MvpPresenter(Context context) {
this.mContext = context;
}
//获取数据
public void getData(String q) throws UnsupportedEncodingException {
if (q.isEmpty()) {
mView.showMessage("请输入解梦内容");
return;
}
mView.showLoading();
getDream(q);
}
public void onItemClick(int position) {
List<String> stringList = mDatas.get(position).getList();
StringBuffer sbf = new StringBuffer();
for (String s : stringList) {
sbf.append(s).append("\n\n\n");
}
new SweetAlertDialog(mContext)
.setTitleText(mDatas.get(position).getTitle())
.setContentText(sbf.toString())
.show();
}
private void getDream(String q) throws UnsupportedEncodingException {
String content = URLDecoder.decode(q, "utf-8");
Map<String, Object> options = new HashMap<String, Object>();
options.put("key", "f86ed9f21931cd311deffada92b58ac7");
options.put("full", "1");
options.put("q", content);
subscriber = new Subscriber<List<JuHeDream>>() {
@Override
public void onCompleted() {
mView.hideLoading();
}
@Override
public void onError(Throwable e) {
mView.hideLoading();
mView.showMessage(e.toString());
}
@Override
public void onNext(List<JuHeDream> data) {
for (JuHeDream juheDream:data) {
Logger.e(juheDream.toString());
}
mDatas = data;
mView.setListItem(mDatas);
}
};
HttpJuHeMethods.getInstance().getJokesByHttpResultMap(subscriber,options);
}
public void destory(){
subscriber.unsubscribe();
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".view.MainActivity">
<LinearLayout
android:layout_width="920px"
android:layout_height="130px"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20px"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="680px"
android:layout_height="130px"
android:background="@drawable/shape_query_normal_stroke"
android:orientation="horizontal" >
<ImageView
android:layout_width="57px"
android:layout_height="70px"
android:layout_gravity="center_vertical"
android:layout_marginLeft="40px"
android:src="@drawable/login_yanzhengma"
android:text="设置密码" />
<View
android:layout_width="0.5px"
android:layout_height="match_parent"
android:layout_marginLeft="40px"
android:background="@color/line" />
<EditText
android:id="@+id/id_dream_query"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginLeft="13px"
android:background="@null"
android:hint="请输入解梦的内容"
android:singleLine="true"
android:textColor="@color/textcolor"
android:textSize="40px" />
</LinearLayout>
<View
android:layout_width="20px"
android:layout_height="match_parent" />
<Button
android:id="@+id/id_dream_btn"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:background="@drawable/query"
android:clickable="true"
android:gravity="center"
android:text="查询"
android:textColor="@android:color/white"
android:textSize="40px" />
</LinearLayout>
<ListView
android:id="@+id/id_dream_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
/>
</LinearLayout>
MainActivity
public class MainActivity extends BaseMvpActivity<MvpView, MvpPresenter> implements MvpView, AdapterView.OnItemClickListener {
@BindView(R.id.id_dream_query)
EditText dreamQuery;
@BindView(R.id.id_dream_btn)
Button dreamBtn;
@BindView(R.id.id_dream_result)
ListView listView;
private Context mContext;
MyAdapter myAdapter;
SweetAlertDialog pd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
ButterKnife.bind(this);
initEvent();
}
private void initEvent() {
listView.setOnItemClickListener(this);
}
@OnClick(R.id.id_dream_btn)
public void onClick() {
try {
String q = dreamQuery.getText().toString();
presenter.getData(q);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public MvpPresenter initPresenter() {
return new MvpPresenter(this);
}
@Override
public void setListItem(List<JuHeDream> data) {
if (myAdapter == null){
myAdapter = new MyAdapter(mContext, data);
}
if (listView.getAdapter() == null){
listView.setAdapter(myAdapter);
}
myAdapter.refresh(data);
}
@Override
public void showMessage(String messgae) {
Toast.makeText(mContext, messgae, Toast.LENGTH_SHORT).show();
}
@Override
public void showLoading() {
if (pd == null) {
pd = new SweetAlertDialog(mContext, SweetAlertDialog.PROGRESS_TYPE);
pd.getProgressHelper().setBarColor(Color.parseColor("#A5DC86"));
pd.setTitleText("Loading");
pd.setCancelable(true);
}
pd.show();
}
@Override
public void hideLoading() {
pd.hide();
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
presenter.onItemClick(position);
}
@Override
protected void onDestroy() {
presenter.destory();
super.onDestroy();
}
}
源码地址:https://github.com/Javen205/RxMVP
Retrofit2+Rxjava+MVP实践的更多相关文章
- Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP
Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP 项目截图 这是我的目录结构 五步使用RxJava+Retrofit2+Okhttp+RxCache 第一步 ...
- Android 基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器aaa
MDPlayer万能播放器 MDPlayer,基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器,可以播 ...
- MVP 实践
今天有时间看了看google的官方文档,下载todo源码,仔细研读了一下,觉得其思想对开发还是有很大帮助的.个人认为,MVP通过Activity与业务逻辑的解耦,其作为Controller的职责更加单 ...
- Retrofit2+Rxjava+OkHttp的使用和网络请求
Retrofit2+Rxjava+OkHttp的使用和网络请求 https://blog.csdn.net/huandroid/article/details/79883895 加入Rxjava 如果 ...
- RxJava操作符实践:8_算术和聚合操作之3_min
发射原始Observable的最小值. Min操作符操作一个发射数值的Observable并发射单个值:最小的那个值. RxJava中,min属于rxjava-math模块. min接受一个可选参数, ...
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(一)
首先,展示一下封装好之后的项目的层级结构. 1.先创建一个RetrofitApiService.java package com.xdw.retrofitrxmvpdemo.http; import ...
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了
在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...
- [Android] 转-RxJava+MVP+Retrofit+Dagger2+Okhttp大杂烩
原文url: http://blog.iliyun.net/2016/11/20/%E6%A1%86%E6%9E%B6%E5%B0%81%E8%A3%85/ 这几年来android的网络请求技术层出不 ...
- retrofit2+rxjava+okhttp网络请求实现
第一步:添加依赖: compile 'io.reactivex:rxandroid:1.2.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.1. ...
随机推荐
- luoguP3952 [NOIP2017]时间复杂度 模拟
原本只是想看下多久能码完时间复杂度 然后在30min内就码完了,然后一A了???? 首先,这题完全可以离线做 我们先把所有的操作读完,判断合不合法之后,再去判断和标准答案的关系 具体而言 把所有的操作 ...
- bzoj 2244
没有正确分析路径可能的条数,它是指数增长的,会爆long long. 然后就是正反两次时间分治. 另一个就是max with count,即带计数的最值,即除了记录最值,还要记录最值取得的次数. /* ...
- NOIP2018 RP++
飞吧,不用看向地面. NOIP,RP++.
- HDU 5683 zxa and xor 暴力模拟
zxa and xor 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5683 Description zxa had a great interes ...
- Python编程练习题学习汇总
实例一:数学计算 简述:这里有四个数字,分别是:1.2.3.4提问:能组成多少个互不相同且无重复数字的三位数?各是多少? Python解题思路分析:可填在百位.十位.个位的数字都是1.2.3.4.组成 ...
- 机器学习(2):Softmax回归原理及其实现
Softmax回归用于处理多分类问题,是Logistic回归的一种推广.这两种回归都是用回归的思想处理分类问题.这样做的一个优点就是输出的判断为概率值,便于直观理解和决策.下面我们介绍它的原理和实现. ...
- 设置ubuntu 终端显示路径长度
~/.bashrc 这个文件记录了用户终端配置. 打开~/.bashrc 这个文件 $: sudo vim ~/.bashrc 找到 将蓝色的w由小写改成大写,可以表示只显示当前目录名称.
- PostgreSQL教程收集(中文文档/命令行工具/常用命令)
http://www.postgres.cn/docs/9.6/index.html(中文文档) https://www.postgresql.org/docs/10/static/auth-meth ...
- [Database] Redis 随笔
Redis 随笔 1. 特点 非关系数据库 non-relational database 内存数据库 高性能 主从复制 可持久化存储 发布与订阅 支持脚本 2. 数据类型5种 STRING 可以是字 ...
- mongodb exception in initAndListen: 12596 old lock file, terminating解决方法
错误信息如下: exception old lock file, terminating 解决方法 .删除data目录中的.lock文件 .mongod.exe --repair .启动mongod就 ...