装逼开始之前,为大家推荐两篇文章,用来更好的学习Retrofit和Rxjava。在这里我们要感谢互联网装逼行业勇于献身,甘于奉献的的大婶们。我仅代表个人,给您们跪舔了。
Retrofit:Retrofit官网
Rxjava:给 Android 开发者的 RxJava 详解
---------------这是分割线---------------
首先配置支持的gradle文件:
compile 'io.reactivex:rxjava:1.1.3'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.1'
截止至本文发表前,上述支持库都是最新版本。
贴出Retrofit官网的GET请求示例:GitHubService接口
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
网络请求部分代码为:
String baseUrl = "https://*******";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call> repos = service.listRepos("octocat");
repos.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
Log.i("onResponse",response.body().toString());
}
@Override
public void onFailure(Call call, Throwable t) {
Log.i("onResponse",t.getMessage());
}
});
addConverterFactory(GsonConverterFactory.create())为设置json解析方式为Gson。
retrofit.create采用动态代理的方式获取GitHubService对象,并通过Callback获取返回的数据。
---------------当Retrofit与Rxjava相遇----------------
Retrofit.Builder需要调用
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
方法,表示用Rxjava做回调,即Rxjava所讲的观察者模式。那么网络请求接口就需要改成如下方式:
Observable> listRepos(@Path("user") String user);
网络请求部分的代码则更改为:
String baseUrl = "https://*******";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
service.listRepos("octocat")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onCompleted() {
Log.i("onCompleted","onCompleted");
}
@Override
public void onError(Throwable e) {
Log.i("onError",e.toString());
}
@Override
public void onNext(XXXEntity movieEntity) {
Log.i("onCompleted",movieEntity.toString());
}
});
如果仔细阅读过上述两篇文章,不难理解这部分代码的含义,由于篇幅原因,这里就不在重复了。
当然如此这般的结合,无法满足对代码有深度洁癖的骚年们。接下来,在此基础上,对代码做整体的封装。
项目目录结构如下:
首先封装网络请求类HTTPHelper.java
/**
* 这一部分配置常量,可以抽取出常量类
*/
private static final String BASE_PATH = "http://www.weather.com.cn/";//访问的地址
private static final long DEFAULT_TIMEOUT = 5000;//默认超时时间(毫秒)
private Retrofit mRetrofit;
private INetService mNetService;
private HTTPHelper(){
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.addInterceptor(new HTTPInterceptor());
okHttpClient.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
mRetrofit = new Retrofit.Builder()
.client(okHttpClient.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(BASE_PATH)
.build();
mNetService = mRetrofit.create(INetService.class);
}
/**
* 单例控制器
*/
private static class SingletonHolder{
private static final HTTPHelper INSTANCE = new HTTPHelper();
}
/**
* 获取单例对象
* @return
*/
public static HTTPHelper getInstance(){
return SingletonHolder.INSTANCE;
}
我们需要将网络请求回来的字符串转换成javaBean对象,所以引入Rxjava的map转换机制。代码如下:
private class HttpResultFunc implements Func1 {
@Override
public T call(IModel iModel) {
if (iModel == null){
try {
throw new Exception("result model is null");
} catch (Exception e) {
e.printStackTrace();
}
}
return (T)iModel;
}
}
到此,配置阶段结束,下面将是Rxjava的异步订阅请求网络并返回操作。为了方便Activity、Fragment等界面处理数据,封装Subscriber接口:
package demo.myframework.common;
import rx.Subscriber;
/**
* @Author: lizhipeng
* @Data: 16/4/12 下午4:17
* @Description: 自定义调阅者以及结果监听接口
*/
public class ResultSubscriber extends Subscriber {
private int mRequestType;
private OnResultListener mListener = null;
/**
* 自定义订阅,参数用来区分网络接口,以用来在不同接口操作过程中,处理不同的逻辑
* @param requestType
*/
public ResultSubscriber(int requestType) {
this.mRequestType = requestType;
mListener = new OnResultListener() {
@Override
public void onStart(int requestType) {
}
@Override
public void onCompleted(int requestType) {
}
@Override
public void onError(Throwable e, int requestType) {
}
@Override
public void onNext(T t, int requestType) {
}
};
}
@Override
public void onStart() {
mListener.onStart(mRequestType);
}
@Override
public void onCompleted() {
mListener.onCompleted(mRequestType);
}
@Override
public void onError(Throwable e) {
if (e != null){
mListener.onError(e,mRequestType);
}
}
@Override
public void onNext(T t) {
mListener.onNext(t,mRequestType);
}
/**
* 设置订阅监听器
* @param listener
*/
public void setOnResultListener(OnResultListener listener){
if (listener != null){
mListener = listener;
}
}
/**
* 订阅的监听器
* @param
*/
public interface OnResultListener {
/**
* 网络请求订阅开始
*/
void onStart(int requestType);
/**
* 网络请求完成
*/
void onCompleted(int requestType);
/**
* 网络请求错误
*/
void onError(Throwable e,int requestType);
/**
* 处理请求结果
*/
void onNext(T t,int requestType);
}
}
已天气访问为例网络请求接口为:
package demo.myframework.interfaces;
import demo.myframework.model.WeatherModel;
import retrofit2.http.GET;
import retrofit2.http.Path;
import rx.Observable;
/**
* @Author: lizhipeng
* @Data: 16/4/12 下午2:57
* @Description: 网络请求接口
*/
public interface INetService {
@GET("data/cityinfo/{city_id}.html")
Observable getWeather(@Path("city_id") String city);
}
HTTPHelper.java 中 网络请求数据方法的实现为:
/**
* 获取网络数据的方法
* @param cityId
*/
public void getWeather(String cityId, int resultType, ResultSubscriber.OnResultListener listener){
ResultSubscriber subscriber = new ResultSubscriber<>(resultType);
subscriber.setOnResultListener(listener);
mNetService.getWeather(cityId)
.map(new HttpResultFunc())
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
MainActivity实现OnResultListener接口,点击按钮调用方法为
HTTPHelper.getInstance().getWeather("101010300",CODE,MainActivity.this);
一下是activity的全部代码:
package demo.myframework.activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import demo.myframework.R;
import demo.myframework.common.ResultSubscriber;
import demo.myframework.http.HTTPHelper;
import demo.myframework.model.IModel;
import demo.myframework.model.WeatherModel;
public class MainActivity extends AppCompatActivity implements ResultSubscriber.OnResultListener{
private static final String TAG = "MainActivity";
private static final int CODE = 1;
private Button mButton;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initData() {
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG,"onClick");
HTTPHelper.getInstance().getWeather("101010300",CODE,MainActivity.this);
}
});
}
private void initView() {
mButton = (Button) findViewById(R.id.button);
mTextView = (TextView) findViewById(R.id.textview);
}
private void setResultSubscriber(){
}
/**
* 网络请求前调用,通常显示Progressialog
* @param requestType
*/
@Override
public void onStart(int requestType) {
Log.i(TAG,"onStart");
}
/**
* 网络请求完成调用,通常销毁Progressialog
* @param requestType
*/
@Override
public void onCompleted(int requestType) {
Log.i(TAG,"onCompleted");
}
/**
* 网络请求错误后调用
* @param e
* @param requestType
*/
@Override
public void onError(Throwable e, int requestType) {
Log.i(TAG,"onError");
}
/**
* onNext 方法中处理请求下来的数据
* @param iModel
* @param requestType
*/
@Override
public void onNext(IModel iModel, int requestType) {
Log.i(TAG,"onNext");
if (requestType == CODE){
mTextView.setText(((WeatherModel)iModel).getWeatherinfo().toString());
}
}
}
HTTPInterceptor.java
package demo.myframework.http;
import android.util.Log;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* @Author: lizhipeng
* @Data: 16/4/12 下午5:19
* @Description: 定义http拦截器,用于设置http协议和日志调试
*/
public class HTTPInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
//封装headers
Request request = chain.request().newBuilder()
.addHeader("Content-Type", "application/json") //添加请求头信息
.build();
// Headers headers = request.headers();
String requestUrl = request.url().toString(); //获取请求url地址
String methodStr = request.method(); //获取请求方式
RequestBody body = request.body(); //获取请求body
String bodyStr = (body==null?"":body.toString());
//打印Request数据
Log.i("HTTP-Interceptor","requestUrl=====>"+requestUrl);
Log.i("HTTP-Interceptor","requestMethod=====>"+methodStr);
Log.i("HTTP-Interceptor","requestBody=====>"+body);
Response response = chain.proceed(request);
return response;
}
}
WeatherModel.java
package demo.myframework.model;
/**
* @Author: lizhipeng
* @Data: 16/4/12 下午3:16
* @Description: 天气信息模板
*/
public class WeatherModel implements IModel{
/**
* city : 朝阳
* cityid : 101010300
* temp1 : -2℃
* temp2 : 16℃
* weather : 晴
* img1 : d0.gif
* img2 : n0.gif
* ptime : 18:00
*/
private WeatherinfoBean weatherinfo;
public WeatherinfoBean getWeatherinfo() {
return weatherinfo;
}
public void setWeatherinfo(WeatherinfoBean weatherinfo) {
this.weatherinfo = weatherinfo;
}
public static class WeatherinfoBean {
private String city;
private String cityid;
private String temp1;
private String temp2;
private String weather;
private String img1;
private String img2;
private String ptime;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCityid() {
return cityid;
}
public void setCityid(String cityid) {
this.cityid = cityid;
}
public String getTemp1() {
return temp1;
}
public void setTemp1(String temp1) {
this.temp1 = temp1;
}
public String getTemp2() {
return temp2;
}
public void setTemp2(String temp2) {
this.temp2 = temp2;
}
public String getWeather() {
return weather;
}
public void setWeather(String weather) {
this.weather = weather;
}
public String getImg1() {
return img1;
}
public void setImg1(String img1) {
this.img1 = img1;
}
public String getImg2() {
return img2;
}
public void setImg2(String img2) {
this.img2 = img2;
}
public String getPtime() {
return ptime;
}
public void setPtime(String ptime) {
this.ptime = ptime;
}
@Override
public String toString() {
return "WeatherinfoBean{" +
"city='" + city + '\'' +
", cityid='" + cityid + '\'' +
", temp1='" + temp1 + '\'' +
", temp2='" + temp2 + '\'' +
", weather='" + weather + '\'' +
", img1='" + img1 + '\'' +
", img2='" + img2 + '\'' +
", ptime='" + ptime + '\'' +
'}';
}
}
}
注释已经在代码中详细说明,就不做太多解释了,着重说一点,ResultSubscriber.java中的mRequestType是用来在连续多次请求网络接口时,需要在界面中做不同的处理而区分的属性。使用时,最好也为每个接口配置为对应的唯一值。
附上GitHub地址,https://github.com/QiYuan007/EasyFrame 如果本文对你有帮助,多多start。
如果你有更好的实现方式,请与我联系。