本章主要针对RxJava
、Retrofit
和OkHttp
结合使用,现在说明一下三者的职责所在。
OkHttp
:负责网络请求;
Retrofit
:主要负责网络请求接口的封装,结合OkHttp
可以处理网络请求的结果;
RxJava
:负责网络请求的异步;
(1)权限
网络请求别忘了添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
(2)依赖
- RxJava依赖
implementation 'io.reactivex.rxjava2:rxjava:2.1.3'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
或者
implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha2'
如果使用rxbinding,就添加rxbinding相关依赖,rxbinding依赖本身支持rxjava和rxandroid,所以如果添加rxbinding依赖就可以去除rxjava和rxandroid依赖了。
- okhttp3依赖
implementation 'com.squareup.okhttp3:okhttp:3.14.0'
- retrofit依赖
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
- 其它辅助依赖
//gson依赖
implementation 'com.google.code.gson:gson:2.8.5'
//gson转换器依赖
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
//日志拦截器依赖
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
(3)具体实现
public interface SearchFileAPIService {
@FormUrlEncoded
@POST("/selfClaim/interface/carList")
Observable<ArrayList<Car>> getCarList(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://xxxx:7001")
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
SearchFileAPIService retrofitTest = retrofit.create(SearchFileAPIService.class);
Observable<ArrayList<Car>> observable = retrofitTest.getCarList("868256021322879", "862679", "c907d5df8b26550eaf2841ed9bcf51bb44b9ae1b", "d3974829a20747579c90e2004a5ed1c5");
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ArrayList<Car>>() {
@Override
public void onSubscribe(Disposable d) {
//开始请求
}
@Override
public void onNext(ArrayList<Car> cars) {
//成功
for(Car car : cars){
Log.d("aaa", car.getCarNumber());
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
//失败
Log.d("aaa", "onFailure:"+e.getCause() + "\n" + e.getMessage());
}
@Override
public void onComplete() {
//结束请求
}
});
单独使用Retrofit,网络请求的返回值类型是Call
,与RxJava结合使用后返回值变成了observable
,这样做的好处是:
- 可以方便的控制线程
- 可以知道网络请求什么时候开始以及什么时候结束
另外,OkHttp可以设置网络超时以及其他配置。
(4)学会自主封装网络请求
封装网络请求需要大家自主完成,因为不同的项目可能有不同的封装方式,思路如下:
-
onSubscribe
代码网络请求的开始,可以弹出网络请求进度条,onComplete
代表网络请求的结束,可以关闭网络请求进度条; -
onError
可以处理一些网络异常,可用于统一处理; -
onNext
用于处理接口返回的数据; - 一般项目中会存在多个接口,那么我们不可能在将
(3)
中的一大段代码在项目中多次出现,这样造成代码的冗余;
下面我直接贴一下我自己封装之后的代码,用到的技术有RxJava
、Retrofit
、OkHttp
、MVP
、rxjava
(1)
RetrofitAPI.java
- Retrofit接口集中定义
public interface RetrofitAPI {
@FormUrlEncoded
@POST("/selfClaim/interface/carList")
Observable<ArrayList<Car>> getCarList(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
@FormUrlEncoded
@POST("/selfClaim/interface/interface1")
Observable<ArrayList<Car>> getA(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
@FormUrlEncoded
@POST("/selfClaim/interface/interface2")
Observable<ArrayList<Car>> getB(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
}
(2)
RetrofitUtils.java
- 封装了一些Retrofit语句,可以防止代码的冗余;
- 使用单例设计模式防止RetrofitUtils对象内存泄漏;
- 创建日志拦截器,可以拦截报文日志;
- 定义通用方法
getDataFromAPI
,泛型T使接口封装更加通用,结合GsonConverterFactory
一起使用; - 使用
AutoDispose
,使自动取消订阅,防止内存泄漏; - 使用
observable.subscribeOn(Schedulers.io())
,让网络请求在异步线程执行; - 使用
observeOn(AndroidSchedulers.mainThread())
让更新界面的操作在UI线程上执行; - 添加网络请求进度条对话框;
- onError方法里集中处理网络异常情况;
public class RetrofitUtils {
private RetrofitAPI retrofitAPI;
private String BASE_URL = "http://xxx.124.175.239:7001";
private RetrofitUtils(){
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)//设置连接超时时长
.readTimeout(20, TimeUnit.SECONDS)//设置读超时时长
.writeTimeout(20, TimeUnit.SECONDS)//设置写超时时长
.addInterceptor(getHttpLoggingInterceptor())//添加日志拦截器
.build();
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
retrofitAPI = retrofit.create(RetrofitAPI.class);
}
static class SingleHolder{
public static RetrofitUtils instance = new RetrofitUtils();
}
public static RetrofitUtils getInstance(){
return RetrofitUtils.SingleHolder.instance;
}
/**
* 创建日志拦截器
* @return
*/
private HttpLoggingInterceptor getHttpLoggingInterceptor() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(
new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.e("aaa", "log = " + message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return loggingInterceptor;
}
public RetrofitAPI getRetrofitAPI(){
return retrofitAPI;
}
/**
* 通用方法
* @param activity
* @param observable
* @param <T>
*/
public <T> void getDataFromAPI(Activity activity, Observable<T> observable, ResultCallBack callBack){
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//AutoDispose的关键语句
.as(AutoDispose.<T>autoDisposable(AndroidLifecycleScopeProvider.from((LifecycleOwner) activity)))
.subscribe(new Observer<T>() {
@Override
public void onSubscribe(Disposable d) {
//开始请求
if(activity instanceof BaseActivity){
BaseActivity baseActivity = (BaseActivity) activity;
baseActivity.loadingDialogShow("请稍等...");
}
}
@Override
public void onNext(T t) {
//成功
callBack.success(t);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
//失败
Log.d("aaa", "onFailure:"+e.getCause() + "\n" + e.getMessage());
if (e instanceof SocketTimeoutException) {
callBack.failed("网络中断,请检查您的网络状态!");
} else if (e instanceof ConnectException) {
callBack.failed("网络中断,请检查您的网络状态!");
}else{
callBack.failed("未知异常!");
}
if(activity instanceof BaseActivity){
BaseActivity baseActivity = (BaseActivity) activity;
baseActivity.loadingDialogDismiss();
}
}
@Override
public void onComplete() {
//结束请求
if(activity instanceof BaseActivity){
BaseActivity baseActivity = (BaseActivity) activity;
baseActivity.loadingDialogDismiss();
}
}
});
}
}
(3)
网络请求进度条对话框
<!-- 自定义loading dialog -->
<style name="loading_dialog" parent="android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowBackground">@color/bg_dialog_white</item>
<item name="android:windowContentOverlay">@null</item>
</style>
public class BaseActivity extends AppCompatActivity {
private Dialog loadingDialog;
/**
* 弹出进度条
*/
public void loadingDialogShow(String msg) {
TextView tipTextView = null;
if (loadingDialog == null) {
LayoutInflater inflater = LayoutInflater.from(this);
View v = inflater.inflate(R.layout.loading_dialog, null);// 得到加载view
LinearLayout layout = v.findViewById(R.id.dialog_view);// 加载布局
ImageView spaceshipImage = v.findViewById(R.id.img);
tipTextView = v.findViewById(R.id.tipTextView);// 提示文字
// 加载动画
Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.loading_animation);
// 使用ImageView显示动画
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
tipTextView.setText(msg);// 设置加载信息
loadingDialog = new Dialog(this, R.style.loading_dialog);// 创建自定义样式dialog
loadingDialog.setCanceledOnTouchOutside(false);
loadingDialog.setCancelable(true);// 不可以用“返回键”取消
loadingDialog.setContentView(layout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));// 设置布局
}
tipTextView.setText(msg);
if (!loadingDialog.isShowing()) {
loadingDialog.show();
}
}
/**
* 关闭进度条
*/
public void loadingDialogDismiss() {
if (loadingDialog != null && loadingDialog.isShowing()) {
try {
loadingDialog.dismiss();
loadingDialog = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//关闭进度条
loadingDialogDismiss();
}
}
loading_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp" >
<ImageView
android:id="@+id/img"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="center"
android:src="@mipmap/aliwx_img_loading" />
<TextView
android:id="@+id/tipTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:layout_marginLeft="5dp"
android:textColor="#FF34A350"
android:text="数据加载中……"
android:textSize="16sp" />
</LinearLayout>
图标:aliwx_img_loading.png
aliwx_img_loading.png(4)
HttpModel.java
- MVP模式的Model
public class HttpModel {
private String IMEI = "868256021322879";
private String appid = "862679";
private String appkey = "c907d5df8b26550eaf2841ed9bcf51bb44b9ae1b";
private RetrofitAPI retrofitAPI;
public HttpModel(){
retrofitAPI = RetrofitUtils.getInstance().getRetrofitAPI();
}
/**
* 获取车辆列表
*/
public void getCarList(Activity activity, String userID, ResultCallBack callBack){
RetrofitUtils.getInstance().getDataFromAPI(activity, retrofitAPI.getCarList(IMEI, appid, appkey, userID), callBack);
}
/**
* 获取车辆列表
*/
public void getA(Activity activity, String userID, ResultCallBack callBack){
RetrofitUtils.getInstance().getDataFromAPI(activity, retrofitAPI.getA(IMEI, appid, appkey, userID), callBack);
}
/**
* 获取车辆列表
*/
public void getB(Activity activity, String userID, ResultCallBack callBack){
RetrofitUtils.getInstance().getDataFromAPI(activity, retrofitAPI.getB(IMEI, appid, appkey, userID), callBack);
}
}
(5)
IMainView.java
- MVP模式的view
public interface IMainView {
void setResult(String result);
}
(6)
辅助接口
public interface ResultCallBack<T> {
void success(T t);
void failed(String error);
}
(7)
MainPresenter.java
- MVP模式的Presenter
public class MainPresenter {
private HttpModel httpModel;
private IMainView view;
public MainPresenter(IMainView view){
httpModel = new HttpModel();
this.view = view;
}
/**
* 获取车辆列表1
* @param activity
*/
public void getCarList(Activity activity, String userID){
httpModel.getCarList(activity, userID, new ResultCallBack<ArrayList<Car>>() {
@Override
public void success(ArrayList<Car> cars) {
if(cars != null && cars.size() > 0){
view.setResult("已获取到车辆!");
for(int i=0;i<cars.size();i++){
Log.d("aaa", "success:"+cars.get(i).getCarNumber());
}
}else{
view.setResult("没有获取到车辆!");
}
}
@Override
public void failed(String error) {
view.setResult(error);
}
});
}
}
(8)
界面
- 界面上的按钮使用
RxBing
解决抖动问题(防暴力点击); - 在关闭页面的时候将mainPresenter置空,防止内存泄漏
public class MainActivity extends BaseActivity implements IMainView {
private TextView result_text;
private MainPresenter mainPresenter;
@SuppressLint("CheckResult")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
result_text = findViewById(R.id.result_text);
mainPresenter = new MainPresenter(this);
RxView.clicks(findViewById(R.id.bt_1))
.throttleFirst(2, TimeUnit.SECONDS)
//AutoDispose的关键语句
.as(AutoDispose.<Unit>autoDisposable(AndroidLifecycleScopeProvider.from(this)))
.subscribe(new Consumer<Unit>() {
@Override
public void accept(Unit unit) throws Exception {
//获取车辆别表
mainPresenter.getCarList(MainActivity.this, "d3974829a20747579c90e2004a5ed1c5");
}
});
}
@Override
public void setResult(String result) {
//显示结果
result_text.setText(result);
}
@Override
protected void onDestroy() {
super.onDestroy();
mainPresenter = null;
}
}
网友评论