Android 网络请求封装(Retrofit+OkHttp+RxJava+AutoDispose),解决网络请求引起的内存泄漏

Retrofit本质上是网络请求的封装库,并没有参与真正的网络请求操作,他为我们提供丰富的注解,用更优雅的方式包装网络请求需要的各个元素;

OkHttp完成真正的网络请求操作,接收Retrofit获取的请求地址、请求头、参数等信息发起网络请求,获取网络数据;

RxJava处理异步操作,他提供了丰富强大的操作符,使用RxJava来完成网络请求过程中繁琐的线程调度;

AutoDispose,使用AutoDispose让网络请求订阅事件与Activity/Fragment生命周期关联,在页面销毁时,取消网络请求订阅事件,避免因为网络请求结果未返回用户关闭页面引起的内存泄露问题。

1、申请网络权限

<uses-permission android:name="android.permission.INTERNET" />

2、Android 9.0以后对不安全链接做了限制,推荐使用https请求,如果使用http需要配置如下:

  在res资源文件目录下新建xml文件夹,新建network_security_config.xml文件

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

  在应用application节点下配置

android:networkSecurityConfig="@xml/network_security_config"

3、引入所需依赖

// 网络组件
api 'com.squareup.retrofit2:retrofit:2.5.0'
api 'com.squareup.retrofit2:converter-gson:2.5.0'
api 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
api 'com.squareup.retrofit2:converter-scalars:2.5.0'
api 'com.squareup.okhttp3:logging-interceptor:4.7.2'
// 异步组件
api 'io.reactivex.rxjava2:rxandroid:2.1.1'
api 'io.reactivex.rxjava2:rxjava:2.2.19'
// rxjava扩展
api 'com.uber.autodispose:autodispose-android-archcomponents:1.3.0'
// json解析
api 'com.google.code.gson:gson:2.8.9'

4、核心类RetrofitHelper,使用单例模式

public class RetrofitHelper {

    //baseUrl
    public static String BASE_URL;

    private static volatile RetrofitHelper instance;

    private final Retrofit.Builder retrofitBuilder;


    /**
     * 使用默认BASE_URL
     *
     * @return
     */
    public Retrofit getRetrofit() {
        return getRetrofit(null);
    }

    /**
     * 方法重载
     *
     * @param baseUrl baseUrl不为空,替换默认BASE_URL
     * @return
     */
    public Retrofit getRetrofit(String baseUrl) {
        Retrofit retrofit;
        if (TextUtils.isEmpty(baseUrl)) {
            retrofit = retrofitBuilder.baseUrl(BASE_URL).build();
        } else {
            retrofit = retrofitBuilder.baseUrl(baseUrl).build();
        }
        return retrofit;
    }

    private RetrofitHelper() {

        //默认BASE_URL赋值
        BASE_URL = "http://www.baidu.com/";

        //构建OkHttpClient对象
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        //日志拦截器
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        builder.addInterceptor(loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY))
                .addInterceptor(getRequestInterceptor())
                .addInterceptor(getHeaderInterceptor())
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(45, TimeUnit.SECONDS)
                .writeTimeout(45, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);
        OkHttpClient okHttpClient = builder.build();

        //创建retrofit构建者对象
        retrofitBuilder = new Retrofit.Builder();
        retrofitBuilder.client(okHttpClient)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create());
    }

    public static RetrofitHelper getInstance() {
        if (instance == null) {
            synchronized (RetrofitHelper.class) {
                if (instance == null) {
                    instance = new RetrofitHelper();
                }
            }
        }
        return instance;
    }

    /**
     * 添加公用的头部内容
     */
    @NonNull
    private Interceptor getHeaderInterceptor() {
        return chain -> {
            Request originalRequest = chain.request();
            Request.Builder builder = originalRequest.newBuilder();

            builder.method(originalRequest.method(), originalRequest.body());
            Request request = builder.build();
            return chain.proceed(request);
        };
    }

    /**
     * 添加公用的 query 参数
     */
    @NonNull
    private Interceptor getRequestInterceptor() {
        return chain -> {
            Request originalRequest = chain.request();

            // 添加新的参数
            HttpUrl.Builder authorizedUrlBuilder = originalRequest.url()
                    .newBuilder()
                    .scheme(originalRequest.url().scheme())
                    .host(originalRequest.url().host())
//                    .addQueryParameter("clientType", "mobile")
                    ;

            // 新的请求
            Request newRequest = originalRequest.newBuilder()
                    .method(originalRequest.method(), originalRequest.body())
                    .url(authorizedUrlBuilder.build())
                    .build();

            return chain.proceed(newRequest);
        };
    }

}

5、定义响应模板类,与后台接口约定

/**
 * 返回模板类,根据实际情况调整
 */
public class ResponseModel<T> implements Serializable {

    /**
     * 请求成功code值
     */
    public static final int SUCCESS = 0;

    private int code;
    private String msg;
    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "ResponseModel{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}

6、定义网络请求回调接口

public interface CallBackLis<T> {

    void onSuccess(String method, T content);

    void onFailure(String method, String error);

}

7、网络请求失败,根据异常类型给出友好提示

public class HttpStatusCode {

    public static String code2info(int statusCode) {
        String info;
        switch (statusCode) {
            case 200:
                info = "请求成功";
                break;
            case 400:
                info = "错误请求";
                break;
            case 401:
                info = "未授权或授权过期";
                break;
            case 403:
                info = "服务器拒绝请求";
                break;
            case 404:
                info = "请求方法不存在";
                break;
            case 414:
                info = "请求地址过长";
                break;
            case 415:
                info = "不支持的媒体类型";
                break;
            case 500:
                info = "服务器内部错误";
                break;
            case 502:
                info = "错误网关";
                break;
            case 503:
                info = "服务不可用";
                break;
            case 504:
                info = "网关超时";
                break;
            default:
                info = "状态码:" + statusCode;
        }

        return info;
    }


    public static String handleException(Throwable e) {
        if (e instanceof HttpException) {
            HttpException httpException = (HttpException) e;
            int statusCode = httpException.code();
            return code2info(statusCode);
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            return "解析错误";
        } else if (e instanceof ConnectException) {
            return "连接超时";
        } else if (e instanceof SocketTimeoutException) {
            return "响应超时";
        } else {
            return "未知错误";
        }
    }

}

8、网络请求回调统一处理类,只保留对我们有用的数据

public class HttpCall {

    /**
     * 网络请求结果过滤
     *
     * @param owner
     * @param observable
     * @param callBackLis
     * @param flag
     * @param <T>
     */
    public static <T> void doCall(LifecycleOwner owner, Observable<ResponseModel<T>> observable, final CallBackLis<T> callBackLis, final String flag) {

        if (observable == null || callBackLis == null) {
            throw new IllegalArgumentException("observable或callBackLis为空");
        }

        //观察者_网络请求状态
        SimpleObserver<ResponseModel<T>> observer = new SimpleObserver<ResponseModel<T>>() {

            @Override
            public void onNext(ResponseModel<T> responseModel) {
                try {
                    if (responseModel != null) {
                        if (responseModel.getCode() == ResponseModel.SUCCESS) {
                            callBackLis.onSuccess(flag, responseModel.getData());
                        } else {
                            callBackLis.onFailure(flag, responseModel.getMsg());
                        }
                    } else {
                        callBackLis.onFailure(flag, "请求数据异常!");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    callBackLis.onFailure(flag, "解析错误!");
                }
            }

            @Override
            public void onError(Throwable e) {
                callBackLis.onFailure(flag, HttpStatusCode.handleException(e));
            }

        };

        if (owner == null) {
            //被观察者订阅观察者,根据生命周期取消订阅,子线程订阅主线程观察
            observable.subscribeOn(Schedulers.newThread())
                    .unsubscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(observer);
        } else {
            //被观察者订阅观察者,根据生命周期取消订阅,子线程订阅主线程观察
            observable.subscribeOn(Schedulers.newThread())
                    .unsubscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    //AutoDispose通过LifecycleOwner与Activity生命周期关联,页面销毁时取消网络请求订阅
                    .as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(owner, Lifecycle.Event.ON_DESTROY)))
                    .subscribe(observer);
        }
    }

    /**
     * 该方法不过滤返回数据
     *
     * @param owner
     * @param observable
     * @param callBackLis
     * @param flag
     * @param <T>
     */
    public static <T> void doCallWithoutIntercept(LifecycleOwner owner, Observable<T> observable, final CallBackLis<T> callBackLis, final String flag) {

        if (observable == null || callBackLis == null) {
            throw new IllegalArgumentException("observable或callBackLis为空");
        }

        //观察者_网络请求状态
        SimpleObserver<T> observer = new SimpleObserver<T>() {

            @Override
            public void onNext(T t) {
                try {
                    if (t != null) {
                        callBackLis.onSuccess(flag, t);
                    } else {
                        callBackLis.onFailure(flag, "请求数据异常!");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    callBackLis.onFailure(flag, "解析错误!");
                }
            }

            @Override
            public void onError(Throwable e) {
                callBackLis.onFailure(flag, HttpStatusCode.handleException(e));
            }

        };

        if (owner == null) {
            observable.subscribeOn(Schedulers.newThread())
                    .unsubscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(observer);
        } else {
            observable.subscribeOn(Schedulers.newThread())
                    .unsubscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    //AutoDispose通过LifecycleOwner与Activity生命周期关联,页面销毁时取消网络请求订阅
                    .as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(owner, Lifecycle.Event.ON_DESTROY)))
                    .subscribe(observer);
        }
    }

}

通过以上操作,网络请求库就封装完成了,使用方法如下:

1、创建Retrofit接口Api,定义接口方法

//加入RxJava之后,定义返回类型为Observable类型
@POST("拼接参数")
Observable<ResponseModel<具体data类型>> login(@Body RequestBody requestBody);

2、创建HttpRequest类

public static void login(LifecycleOwner owner, CallBackLis<具体data类型> callBackLis) {

    RequestBody requestBody = HttpUtils.getRequestBody("{\"loginName\":\"loginName\"}");

    Observable<ResponseModel<具体data类型>> observable = RetrofitHelper
            .getInstance()
            .getRetrofit()
            .create(Api.class)
            .login(requestBody);
    HttpCall.doCall(owner, observable, callBackLis, null);
}

3、在Activity/Fragment中调用方法

HttpRequest.login(activity, new CallBackLis<具体data类型>() {
    @Override
    public void onSuccess(String method, 具体data类型 content) {
        //content为我们需要的数据

    }

    @Override
    public void onFailure(String method, String error) {
        toast(error);
    }
});

最后附上完整demo,点击查看icon-default.png?t=LA92https://github.com/xsb0426/NetworkDemo

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值