【Android -- 网络请求】Rxjava + Retrofit 简单封装

前言

Retrofit: 是 Square 公司开发的一款正对Android 网络请求的框架。底层基于OkHttp 实现,OkHttp 已经得到了google 官方的认可。RxJava 就是一种用 Java 语言实现的响应式编程,是一个基于事件订阅的异步执行的一个类库,核心思想是观察者模式。

效果图

image.png

配置

  • build.gradle 中添加相关库:
    // 网络请求
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.2.10'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'com.google.code.gson:gson:2.8.9'

    implementation 'io.github.youth5201314:banner:2.2.2'
    //glide
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
  • 添加权限
     <!--联网权限-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--检测网络状态权限-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!-- 在SDCard中创建与删除文件权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
        tools:ignore="ProtectedPermissions"/>
    <uses-permission android:name="android.permission.WRITE_SETTINGS"
        tools:ignore="ProtectedPermissions"/>
    <!-- 往SDCard写入数据权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- 从SDCard读取数据权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
封装前简单使用
/**
     * 封装之前简单使用
     */
    public void normalRequest(View view) {
        //第一步:创建Retrofit
        Retrofit mRetrofit = new Retrofit.Builder()
                .baseUrl(Constants.BASEURL)//添加BaseUrl
                .client(MyApplication.mOkHttpClient)//添加OkhttpClient
                .addConverterFactory(GsonConverterFactory.create())//添加Gson解析
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//  添加 rxjava 支持
                .build();

        //第二步:构建接口
        APIService iApiService = mRetrofit.create(APIService.class);

        //第三步:构建被观察者对象
        Observable<BaseBean<List<BannerBean>>> observable = iApiService.getBanner();

        //第四步:订阅
        observable.subscribeOn(Schedulers.io())//指定Observable自身在io线程中执行
                .observeOn(AndroidSchedulers.mainThread())//指定一个观察者在主线程中国观察这个Observable
                .subscribe(new Observer<BaseBean<List<BannerBean>>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e("TAG", "开始之前");
                    }

                    @Override
                    public void onNext(BaseBean<List<BannerBean>> listBaseBean) {
                        Toast.makeText(MainActivity.this, listBaseBean.getData().toString(), Toast.LENGTH_SHORT).show();
                        Log.e("TAG", "成功");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Toast.makeText(MainActivity.this, "失败", Toast.LENGTH_SHORT).show();
                        Log.e("TAG", "失败");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "结束");
                    }
                });
    }

封装

  1. 创建 RetrofitClient
/**
 * Created on 2021/12/28 14:11
 *
 * @author Kevin
 */
public class RetrofitClient {
    public static Retrofit mRetrofit;

    /**
     * 为我们的Client配置参数,使用静态语句块来配置
     * 只执行一次,运行一开始就开辟了内存,内存放在全局
     */
    static {
        mRetrofit = new Retrofit.Builder()
                .baseUrl(Constants.BASEURL)//添加BaseUrl
                .client(MyApplication.mOkHttpClient)//添加OkhttpClient
                .addConverterFactory(GsonConverterFactory.create())//添加Gson解析
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//  添加 rxjava 支持
                .build();
    }

    /**
     * 所有请求都放在一个接口中
     */
    public static APIService createApi() {
        return mRetrofit.create(APIService.class);
    }

    /**
     * 不同请求放不同接口中
     * @param service 指定接口
     */
    public static <T> T createApi(Class<T> service) {
        return mRetrofit.create(service);
    }


    /**
     * @param context 上下文
     * @param observable 被观察者
     * @param listener 回调接口
     * @param requstName 接口名称
     * @param <T> 实体类
     */
    public static <T> void request(Context context, Observable<T> observable,
                                   final IResponseCallBack<T> listener, String requstName) {
        Constants.requestName = requstName;
        if (!Utils.isConnected(MyApplication.context)) {
            if (listener != null) {
                listener.onFail(new OkHttpException(-1, "网络不可用,请检查网络"));
            }
            return;
        }
        observable.subscribeOn(Schedulers.io())//指定Observable自身在io线程中执行
                .observeOn(AndroidSchedulers.mainThread())//指定一个观察者在主线程中国观察这个Observable
                .subscribe(new CallBackObserver<T>(listener, context));//订阅

    }

    /**
     * 统一下载图片共用
     * @param observable 被观察者
     * @param callback 回调接口
     * @param imgPath 存储地址
     * @param requstName 功能名称
     */
    public static void downImg(Observable<ResponseBody> observable,
                               final IResponseByteCallBack callback, final String imgPath, String requstName) {
        Constants.requestName = requstName;
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ResponseBody>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(ResponseBody responseBody) {
                        File file = null;
                        try {
                            InputStream is = responseBody.byteStream();
                            int len = 0;
                            // 文件夹路径
                            String pathUrl =
                                    Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
                                            + "/PJS/";
                            File filepath = new File(pathUrl);
                            if (!filepath.exists()) {
                                filepath.mkdirs();// 创建文件夹
                            }
                            file = new File(pathUrl, imgPath);

                            FileOutputStream fos = new FileOutputStream(file);

                            byte[] buf = new byte[2048];
                            while ((len = is.read(buf)) != -1) {
                                fos.write(buf, 0, len);
                            }
                            fos.flush();
                            fos.close();
                            is.close();
                            callback.onSuccess(file);
                        } catch (final Exception e) {
                            callback.onFailure(e.getMessage());
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        callback.onFailure(e.getMessage());
                    }

                    @Override
                    public void onComplete() {
                    }
                });

    }
}
  1. 初始化 OkHttpClient.java
/**
 * Created on 2021/12/28 14:22
 *
 * @author Kevin
 */
public class MyApplication extends Application {
    public static Context context;
    public static OkHttpClient mOkHttpClient;
    /**
     * 超时时间
     */
    private static final int TIME_OUT = 30;

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
        initOkHttp();
    }

    private void initOkHttp() {
        //获取缓存路径
        File cacheDir = MyApplication.context.getExternalCacheDir();

        //设置缓存的大小
        int cacheSize = 10 * 1024 * 1024;
        //创建我们Client对象的构建者
        OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
        okHttpBuilder
                //为构建者设置超时时间
                .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                websocket轮训间隔(单位:秒)
                .pingInterval(20, TimeUnit.SECONDS)
                //设置缓存
                .cache(new Cache(cacheDir.getAbsoluteFile(), cacheSize))
                //允许重定向
                .followRedirects(true)
                //设置拦截器
                .addInterceptor(new RequetInterceptor())
                //添加https支持
                .hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                })
                .sslSocketFactory(HttpsUtils.initSSLSocketFactory(), HttpsUtils.initTrustManager());

        mOkHttpClient = okHttpBuilder.build();

    }
}
  1. 观察者 CallBackObserver
/**
 * Created on 2021/12/28 14:05
 *
 * @author Kevin
 */
public class CallBackObserver<T> implements Observer<T> {
    private IResponseCallBack<T> mListener;
    private Activity activity;

    public CallBackObserver(IResponseCallBack<T> listener, Context context) {
        this.mListener = listener;
        this.activity = (Activity) context;
    }

    @Override
    public void onSubscribe(Disposable d) {
        /**
         * 这里可以 显示加载圈等
         */
    }

    /**
     * 成功
     * @param data
     */
    @Override
    public void onNext(T data) {
        if (mListener != null && !activity.isFinishing()) {
            BaseBean baseBean = (BaseBean) data;
            /**
             * 是否成功
             */
            if (baseBean.isSuccess()) {
                mListener.onSuccess(data);
            }else {
                mListener.onFail(new OkHttpException(baseBean.getErrorCode(), baseBean.getErrorMsg()));
            }
        }

    }

    /**
     * 失败
     * @param e
     */
    @Override
    public void onError(Throwable e) {
        onComplete();
        if (mListener != null && !activity.isFinishing()) {
            /**
             * 处理失败原因
             */
            OkHttpException okHttpException = ExceptionHandle.handleException(e,activity);
            if(okHttpException !=null) {
                mListener.onFail(okHttpException);
            }
        }

    }

    @Override
    public void onComplete() {
        /**
         * 这里可以 关闭加载圈等
         */
    }
}
  1. 回调接口 IResponseCallBack.java
/**
 * Created on 2021/12/28 14:09
 * 描述:自定义回调接口
 * @author Kevin
 */
public interface IResponseCallBack<T> {
    void onSuccess(T data);

    void onFail(OkHttpException failuer);
}
  1. 拦截器 RequetInterceptor.java
/**
 * Created on 2021/12/28 14:11
 * 日志拦截器
 * @author Kevin
 */
public class RequetInterceptor implements Interceptor {
    /**
     * 这个chain里面包含了request和response,所以你要什么都可以从这里拿
     */
    @Override
    public Response intercept(Chain chain) throws IOException {

        /**
         * 可以添加公共头部参数如token
         */
        Request request = chain.request()
                .newBuilder()
//        .header("TOKEN", token)
//        .header("ID", id)
                .build();

        /**
         * 开始时间
         */
        long startTime = System.currentTimeMillis();
        Log.e("TAG","\n"+"requestUrl=" + request.url());
        String method = request.method();

        if ("POST".equals(method)) {
            try {
                JSONObject jsonObject = new JSONObject();
                if (request.body() instanceof FormBody) {
                    FormBody body = (FormBody) request.body();
                    for (int i = 0; i < body.size(); i++) {
                        jsonObject.put(body.encodedName(i), body.encodedValue(i));
                    }
                    Log.e("TAG","入参JSON= " + jsonObject.toString());
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        Response response = chain.proceed(request);
        /**
         * 这里不能直接使用response.body().string()的方式输出日志
         * 因为response.body().string()之后,response中的流会被关闭,程序会报错,我们需要创建出一个新的response给应用层处理
         */
        ResponseBody responseBody = response.peekBody(1024 * 1024);
        Log.e("TAG","出参JSON=" + responseBody.string());
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        Log.e("TAG","----------" + Constants.requestName + "耗时:" + duration + "毫秒----------");
        return response;
    }
}
  1. 封装后简单使用
    /**
     * 封装后使用 GET 请求
     */
    public void getData() {
        RetrofitRequest.getBannerApi(context, new IResponseCallBack<BaseBean<List<BannerBean>>>() {
            @Override
            public void onSuccess(BaseBean<List<BannerBean>> data) {
                List<BannerBean> beans = data.getData();
                images.addAll(beans);
            }

            @Override
            public void onFail(OkHttpException failuer) {
                Toast.makeText(MainActivity.this, "失败", Toast.LENGTH_SHORT).show();
                Log.e("TAG", "失败="+failuer.getEmsg());
            }
        });

    }

项目地址:传送门

参考:
深入理解Retrofit源码

Retrofit + RxJava + OkHttp 让网络请求变的简单-基础篇

Retrofit + RxJava + OkHttp 让网络请求变的简单-封装篇

Retrofit 官网

优雅的网络请求框架封装过程

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android网络请求封装可以通过以下步骤实现: 1. 在AndroidManifest.xml文件中添加网络权限,以确保应用程序可以进行网络请求。可以在<manifest>标签内添加以下代码: <uses-permission android:name="android.permission.INTERNET"/> \[1\] 2. 定义一个网络请求回调接口,用于处理请求成功和失败的回调方法。可以创建一个接口,并在接口中定义onSuccess和onFailure方法,如下所示: public interface CallBackLis<T> { void onSuccess(String method, T content); void onFailure(String method, String error); } \[2\] 3. 在Activity或Fragment中调用网络请求方法。可以使用HttpRequest类中的静态方法来发送网络请求,并传入回调接口的实例作为参数。例如: HttpRequest.login(activity, new CallBackLis<具体data类型>() { @Override public void onSuccess(String method, 具体data类型 content) { // 在这里处理请求成功后的逻辑,content为我们需要的数据 } @Override public void onFailure(String method, String error) { // 在这里处理请求失败后的逻辑,error为错误信息 toast(error); } }); \[3\] 通过以上步骤,可以实现Android网络请求封装,使得网络请求的调用更加简洁和方便。 #### 引用[.reference_title] - *1* [初学Android网络封装](https://blog.csdn.net/weixin_43993331/article/details/122151795)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Android 网络请求封装(Retrofit+OkHttp+RxJava+AutoDispose),解决网络请求引起的内存泄漏](https://blog.csdn.net/u013624014/article/details/122000289)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kevin-Dev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值