Android--Retrofit+RxJava的简单封装(三)
1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下
先创建一个HttpMethods类,将Retrofit对象创建封装起来
HttpMethods.java
package com.qianmo.retrofitdemo.http; import com.qianmo.retrofitdemo.entry.MovieEntity; import java.util.concurrent.TimeUnit; import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; /**
* Created by wangjitao on 2016/11/3 0003.
* 对Retrofit的的简单封装
*/
public class HttpMethods { public static final String BASE_URL = "https://api.douban.com/v2/movie/";
private static final int DEFAULT_TIMEOUT = 5; private Retrofit retrofit; private MovieService movieService; //先构造私有的构造方法
private HttpMethods() {
//手动创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); retrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
movieService = retrofit.create(MovieService.class);
} //创建单例
public static class SingleonHolder {
private static final HttpMethods instance = new HttpMethods();
} //获取单例
public static HttpMethods getInstance() {
return SingleonHolder.instance;
} /**
*
* @param start 起始位置
* @param count 获取长度
* @param subscriber 传递过来的观察者对象
*/
public void getTopMovie(int start, int count, Subscriber<MovieEntity> subscriber) {
movieService.getTopMovie(start, count)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
}
在直接在Activity中进行调用
package com.qianmo.retrofitdemo; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast; import com.qianmo.retrofitdemo.entry.MovieEntity;
import com.qianmo.retrofitdemo.http.HttpMethods;
import com.qianmo.retrofitdemo.http.MovieService; import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; public class MainActivity extends AppCompatActivity { @Bind(R.id.tv_show)
TextView tvShow;
@Bind(R.id.btn_request)
Button btnRequest; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
} @OnClick({R.id.btn_request})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_request:
getMovie();
break;
}
} //请求网络数据
private void getMovie() { // //https://api.douban.com/v2/movie/top250?start=0&count=10 目标地址
// String baseUrl = "https://api.douban.com/v2/movie/";
//
// //创建Retrofit对象
// Retrofit retrofit = new Retrofit.Builder()
// .baseUrl(baseUrl)
// .addConverterFactory(GsonConverterFactory.create())
// .build();
//
// MovieService movieService = retrofit.create(MovieService.class);
// Call<MovieEntity> call = movieService.getTopMovie(0, 10);
// call.enqueue(new Callback<MovieEntity>() {
// @Override
// public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
// tvShow.setText(response.body().getTitle());
// }
//
// @Override
// public void onFailure(Call<MovieEntity> call, Throwable t) {
// tvShow.setText(t.getMessage());
// }
// }); //第二种
// String baseUrl = "https://api.douban.com/v2/movie/";
//
// Retrofit retrofit = new Retrofit.Builder()
// .baseUrl(baseUrl)
// .addConverterFactory(GsonConverterFactory.create())
// .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
// .build();
// MovieService movieService = retrofit.create(MovieService.class);
//
// movieService.getTopMovie(0, 10)
// .subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(new Subscriber<MovieEntity>() {
// @Override
// public void onCompleted() {
// Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
// }
//
// @Override
// public void onError(Throwable e) {
// tvShow.setText(e.getMessage());
// }
//
// @Override
// public void onNext(MovieEntity movieEntity) {
// tvShow.setText(movieEntity.getTitle());
// }
// });
HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber<MovieEntity>() {
@Override
public void onCompleted() {
Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
} @Override
public void onError(Throwable e) {
tvShow.setText(e.getMessage());
} @Override
public void onNext(MovieEntity movieEntity) {
tvShow.setText(movieEntity.getTitle());
}
});
} }
但是现在存在一个问题,当存在相同格式的数据时候 我们应该怎么封装,一般来说我们后台返给我们的数据是这样的:
{
"resultCode": 0,
"resultMessage": "成功",
"data": {}
}
主要的数据是data,然后通过code来判断是否请求成功 由于data里面的数据是多变的 可以是一个对象也可以是一个数组 这时候我们需要创建一个HttpResult
package com.qianmo.retrofitdemo.http; /**
* Created by Administrator on 2016/11/3 0003.
*/
public class HttpResult<T> {
private int resultCode ;
private String resultMessage ; private T data ; }
用过我们这次借口的同学都知道我们这次接口其实不是这样的,先来看看我们这次的数据结构吧
{
"count": 10,
"start": 0,
"total": 250,
"subjects": [],
"title": "豆瓣电影Top250"
}
我们打算通过count的数量来判断请求是否成功,所以吧HttpResult类修改成下面
package com.qianmo.retrofitdemo.http; /**
* Created by Administrator on 2016/11/3 0003.
*/
public class HttpResult<T> {
// 常用形式
// private int resultCode ;
// private String resultMessage ;
//
// private T data ; //本次接口的数据结构
private int count;
private int start;
private int total;
private String title; //用来模仿Data
private T subjects; public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public int getStart() {
return start;
} public void setStart(int start) {
this.start = start;
} public int getTotal() {
return total;
} public void setTotal(int total) {
this.total = total;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public T getSubjects() {
return subjects;
} public void setSubjects(T subjects) {
this.subjects = subjects;
} @Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("title=" + title + " count=" + count + " start=" + start);
if (null != subjects) {
sb.append(" subjects:" + subjects.toString());
}
return sb.toString();
} }
在正常服务器返回的数据下code=200或者code=0的时候是表示成功的,但是由于我们这次的接口没有这一块的内容,所以打算使用count字段来判断,当coun = 0的时候表示没有数据,请求失败,所以这里我们需要在HttpMethod类中添加一个判断的方法
/**
* 用来处理请求的code
* @param <T>
*/
private class HttpResultFunc<T> implements Func1<HttpResult<T>, T> {
@Override
public T call(HttpResult<T> tHttpResult) {
if (tHttpResult.getCount() == 0) {
throw new ApiException(100);
}
return tHttpResult.getSubjects();
}
}
所以getMovie() 方法修改成了
/**
* 用于获取豆瓣电影Top250的数据
* @param subscriber 由调用者传过来的观察者对象
* @param start 起始位置
* @param count 获取长度
*/
public void getTopMovie(Subscriber<List<Subject>> subscriber, int start, int count){ movieService.getTopMovie(start, count)
.map(new HttpResultFunc<List<Subject>>())
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
ok,在修改一下activity中的调用方法
HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber<List<Subject>>() {
@Override
public void onCompleted() {
Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
} @Override
public void onError(Throwable e) {
tvShow.setText(e.getMessage());
} @Override
public void onNext(List<Subject> subjects) {
StringBuffer sb = new StringBuffer();
for (Subject subject : subjects) {
sb.append(subject.toString());
}
tvShow.setText(sb);
}
});
让我们看一下效果:(截取的动态图又太大了!!上传不了)
但是这也不是我们想要的最终结果,在请求数据的时候显示加载框,在请求完成的时候或者请求出错的时候影藏掉加载框,这样的话才算一个正常的网络请求框架。由于使用了RxJava,所以要创建一个类,继承与Subscriber,由于Subscriver对象中有四个方法,onStart、onNext、onError、onCompleted方法,我们需要在onStart中显示进度框,在onCompleted和onError中隐藏掉加载框,由于activity只关心最后的数据,所以我们需要写一个接口回调,将onNext方法中的数据传递给activity,让activity去处理逻辑。
SubscriberOnNextListenter.java
package com.qianmo.retrofitdemo.http; /**
* Created by Administrator on 2016/11/3 0003.
*/
public interface SubscriberOnNextListenter<T> {
void next(T t);
}
ProgressSubscriber.java
package com.qianmo.retrofitdemo.http; import android.content.Context;
import android.widget.Toast; import rx.Subscriber; /**
* Created by wangjitao on 2016/11/3 0003.
*/
public class ProgressSubscriber<T> extends Subscriber<T> { private SubscriberOnNextListenter mSubscriberOnNextListenter;
private Context context; public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) {
this.mSubscriberOnNextListenter = mSubscriberOnNextListenter;
this.context = context;
} @Override
public void onStart() {
} @Override
public void onCompleted() {
Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
} @Override
public void onError(Throwable e) {
Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
} @Override
public void onNext(T t) {
mSubscriberOnNextListenter.next(t);
}
}
再来修改一下我们activity调用的代码
package com.qianmo.retrofitdemo; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast; import com.qianmo.retrofitdemo.entry.Subject;
import com.qianmo.retrofitdemo.http.HttpMethods;
import com.qianmo.retrofitdemo.http.ProgressSubscriber;
import com.qianmo.retrofitdemo.http.SubscriberOnNextListenter; import java.util.List; import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
import rx.Subscriber; public class MainActivity extends AppCompatActivity { @Bind(R.id.tv_show)
TextView tvShow;
@Bind(R.id.btn_request)
Button btnRequest; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
} @OnClick({R.id.btn_request})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_request:
getMovie();
break;
}
} //请求网络数据
private void getMovie() { // //https://api.douban.com/v2/movie/top250?start=0&count=10 目标地址
// String baseUrl = "https://api.douban.com/v2/movie/";
//
// //创建Retrofit对象
// Retrofit retrofit = new Retrofit.Builder()
// .baseUrl(baseUrl)
// .addConverterFactory(GsonConverterFactory.create())
// .build();
//
// MovieService movieService = retrofit.create(MovieService.class);
// Call<MovieEntity> call = movieService.getTopMovie(0, 10);
// call.enqueue(new Callback<MovieEntity>() {
// @Override
// public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
// tvShow.setText(response.body().getTitle());
// }
//
// @Override
// public void onFailure(Call<MovieEntity> call, Throwable t) {
// tvShow.setText(t.getMessage());
// }
// }); //第二种
// String baseUrl = "https://api.douban.com/v2/movie/";
//
// Retrofit retrofit = new Retrofit.Builder()
// .baseUrl(baseUrl)
// .addConverterFactory(GsonConverterFactory.create())
// .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
// .build();
// MovieService movieService = retrofit.create(MovieService.class);
//
// movieService.getTopMovie(0, 10)
// .subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(new Subscriber<MovieEntity>() {
// @Override
// public void onCompleted() {
// Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
// }
//
// @Override
// public void onError(Throwable e) {
// tvShow.setText(e.getMessage());
// }
//
// @Override
// public void onNext(MovieEntity movieEntity) {
// tvShow.setText(movieEntity.getTitle());
// }
// });
//第三种
// HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber<List<Subject>>() {
// @Override
// public void onCompleted() {
// Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
// }
//
// @Override
// public void onError(Throwable e) {
// tvShow.setText(e.getMessage());
// }
//
// @Override
// public void onNext(List<Subject> subjects) {
// StringBuffer sb = new StringBuffer();
// for (Subject subject : subjects) {
// sb.append(subject.toString());
// }
// tvShow.setText(sb);
// }
// });
SubscriberOnNextListenter subscriberOnNextListenter = new SubscriberOnNextListenter() {
@Override
public void next(Object o) { }
};
//第四种
HttpMethods.getInstance()
.getTopMovie(0, 10, new ProgressSubscriber<List<Subject>>(
new SubscriberOnNextListenter<List<Subject>>() {
@Override
public void next(List<Subject> subjects) {
StringBuffer sb = new StringBuffer();
for (Subject subject : subjects) {
sb.append(subject.toString());
}
tvShow.setText(sb);
}
}, MainActivity.this)); } }
再加上取消加载的接口和封装的progress就基本上完成了
package com.qianmo.retrofitdemo.http; public interface ProgressCancelListener {
void onCancelProgress();
}
package com.qianmo.retrofitdemo.http; import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message; /**
* Created by liukun on 16/3/10.
*/
public class ProgressDialogHandler extends Handler { public static final int SHOW_PROGRESS_DIALOG = 1;
public static final int DISMISS_PROGRESS_DIALOG = 2; private ProgressDialog pd; private Context context;
private boolean cancelable;
private ProgressCancelListener mProgressCancelListener; public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener,
boolean cancelable) {
super();
this.context = context;
this.mProgressCancelListener = mProgressCancelListener;
this.cancelable = cancelable;
} private void initProgressDialog(){
if (pd == null) {
pd = new ProgressDialog(context); pd.setCancelable(cancelable); if (cancelable) {
pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
mProgressCancelListener.onCancelProgress();
}
});
} if (!pd.isShowing()) {
pd.show();
}
}
} private void dismissProgressDialog(){
if (pd != null) {
pd.dismiss();
pd = null;
}
} @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_PROGRESS_DIALOG:
initProgressDialog();
break;
case DISMISS_PROGRESS_DIALOG:
dismissProgressDialog();
break;
}
} }
progressSubscriber.java
package com.qianmo.retrofitdemo.http; import android.content.Context;
import android.widget.Toast; import java.net.ConnectException;
import java.net.SocketTimeoutException; import rx.Subscriber; /**
* Created by wangjitao on 2016/11/3 0003.
*/
public class ProgressSubscriber<T> extends Subscriber<T> implements ProgressCancelListener { private SubscriberOnNextListenter mSubscriberOnNextListenter;
private ProgressDialogHandler mProgressDialogHandler;
private Context context; public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) {
this.mSubscriberOnNextListenter = mSubscriberOnNextListenter;
this.context = context;
mProgressDialogHandler = new ProgressDialogHandler(context, this, true);
} /**
* 在开始订阅的时候显示加载框
*/
@Override
public void onStart() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
}
} /**
* 在完成的时候进行影藏
*/
@Override
public void onCompleted() {
Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
dismissProgressDialog();
} /**
* 在出错的时候也进行影藏
*
* @param e
*/
@Override
public void onError(Throwable e) {
if (e instanceof SocketTimeoutException) {
Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show();
} else if (e instanceof ConnectException) {
Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
dismissProgressDialog();
} @Override
public void onNext(T t) {
mSubscriberOnNextListenter.next(t);
} @Override
public void onCancelProgress() {
if (!this.isUnsubscribed()) {
this.unsubscribe();
}
} private void showProgressDialog() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
}
} private void dismissProgressDialog() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();
mProgressDialogHandler = null;
}
}
}
最后看一下效果
Android--Retrofit+RxJava的简单封装(三)的更多相关文章
- retrofit+RXjava二次封装
接入说明:项目中已集成RXjava,RXandroid.Retrofit,为避免包冲突,不须要再次接入. 就可以直接使用RXjava,Retrofit的所有api. github地址:https:// ...
- Android Retrofit+RxJava 优雅的处理服务器返回异常、错误
标签: 开始本博客之前,请先阅读: Retrofit请求数据对错误以及网络异常的处理 异常&错误 实际开发经常有这种情况,比如登录请求,接口返回的 信息包括请求返回的状态:失败还是成功,错误码 ...
- Android Retrofit RxJava实现缓存
RxJava如何与Retrofit结合参考:http://blog.csdn.net/jdsjlzx/article/details/52015347 缓存配置 app网络数据的离线缓存实现有很多种办 ...
- 【Android】RxJava的使用(三)转换——map、flatMap
前两篇Android RxJava的使用(一)基本用法.Android RxJava的使用(二)Action介绍了RxJava的基本用法,对Rxjava还不了解的请先看以上两篇.这篇为大家讲解RxJa ...
- Retrofit + RxJava + OkHttp 让网络请求变的简单-基础篇
https://www.jianshu.com/p/5bc866b9cbb9 最近因为手头上的工作做完了,比较闲,想着做一些优化.看到以前用的那一套网络框架添加一个请求比较麻烦,并且比较难用,所以想改 ...
- Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...
- Android MVP开发模式及Retrofit + RxJava封装
代码已上传到Github,因为接口都是模拟无法进行测试,明白大概的逻辑就行了! 欢迎浏览我的博客--https://pushy.site 1. MVP模式 1.1 介绍 如果熟悉MVP模式架构的话,对 ...
- 基于Retrofit+RxJava的Android分层网络请求框架
目前已经有不少Android客户端在使用Retrofit+RxJava实现网络请求了,相比于xUtils,Volley等网络访问框架,其具有网络访问效率高(基于OkHttp).内存占用少.代码量小以及 ...
- 学习RxJava+Retrofit+OkHttp+MVP的网络请求使用
公司的大佬用的是这一套,那我这个菜鸟肯定要学习使用了. 我在网上找了很多文章,写的都很详细,比如 https://www.jianshu.com/u/5fd2523645da https://www. ...
随机推荐
- Emmet:HTML/CSS代码快速编写神器
本文来源:http://www.iteye.com/news/27580 ,还可参考:http://www.w3cplus.com/tools/emmet-cheat-sheet.html Em ...
- Jquery用法
$this.closest("dd").addClass("selected").siblings().removeClass("selected&q ...
- HTML 父窗口打开子窗口,并从子窗口返回值
父窗口:windowdemo.html <html> <head> <title> 接收子窗口返回的内容 </title> <script lan ...
- [LintCode] Sort Integers II 整数排序之二
Given an integer array, sort it in ascending order. Use quick sort, merge sort, heap sort or any O(n ...
- [转载]CRect::DeflateRect
1基本内容 void DeflateRect(int x,int y); void DeflateRect(SIZE size); void DeflateRect(LPCRECT lpRect); ...
- Linux服务器中木马(肉鸡)手工清除方法
由于自己也碰到过这种情况,刚好看到这篇文章,先转载过来.的确蛮有用的哦. 首先剧透一下后门木马如下: (当然这是事后平静下来后慢慢搜出来的,那个时候喝着咖啡感觉像个自由人) 木马名称 Linux.Ba ...
- cocos2d-x渲染流程
Cocos2Dx之渲染流程 发表于8个月前(2014-08-08 22:46) 阅读(3762) | 评论(2) 17人收藏此文章, 我要收藏 赞2 如何快速提高你的薪资?-实力拍“跳槽吧兄弟”梦 ...
- (转)MySQL优化实例
在Apache, PHP,MySQL的体系架构中,MySQL对于性能的影响最大,也是关键的核心部分.对于Discuz!论坛程序也是如此,MySQL的设置是否合理优化,直接影响到论坛的速度和承载量!同时 ...
- BizTalk开发系列(三十八)微软BizTalk Server定价和许可[解读]
做BizTalk的项目一段时间了,但是对BizTalk的价格和许可还不是很了解.给客户设计解决方案时大部分产品都是直接按照企业版的功能来设计,很 少考虑到价格和许可方面的因素,以为这个不是我们的事情或 ...
- 一个应用层的Makefile
CC = gcc #gcc编译器LIB= -lpthread #需要链接的库文件CFLAGS=-std=gnu99 #C编译器的选项,C99标准OBJ=test.o gpio.o #生成的汇编文件PR ...