装逼开始之前,为大家推荐两篇文章,用来更好的学习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<List<Repo>> 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<List<XXXEntity>> repos = service.listRepos("octocat"); repos.enqueue(new Callback<XXXEntity>() { @Override public void onResponse(Call<XXXEntity> call, Response<XXXEntity> response) { Log.i("onResponse",response.body().toString()); } @Override public void onFailure(Call<XXXEntity> 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<List<Repo>> 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<XXXEntity>() { @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<T> implements Func1<IModel, T> { @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<T> extends Subscriber<T> { private int mRequestType; private OnResultListener<T> mListener = null; /** * 自定义订阅,参数用来区分网络接口,以用来在不同接口操作过程中,处理不同的逻辑 * @param requestType */ public ResultSubscriber(int requestType) { this.mRequestType = requestType; mListener = new OnResultListener<T>() { @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 <T> */ public interface OnResultListener<T> { /** * 网络请求订阅开始 */ 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<WeatherModel> getWeather(@Path("city_id") String city); }
HTTPHelper.java 中 网络请求数据方法的实现为:
/** * 获取网络数据的方法 * @param cityId */ public void getWeather(String cityId, int resultType, ResultSubscriber.OnResultListener listener){ ResultSubscriber<IModel> subscriber = new ResultSubscriber<>(resultType); subscriber.setOnResultListener(listener); mNetService.getWeather(cityId) .map(new HttpResultFunc<WeatherModel>()) .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<IModel>{ 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。
如果你有更好的实现方式,请与我联系。