基于Retrofit封装的高效的网络访问工具,使用泛型自动创建ApiService

支持GET、POST、PUT、DELETE 以及文件上传 支持返回指定的数据结果,默认自动解析为传入的实体类 支持Mock数据可配置化,Mock环境随心切换 支持泛型自动创建ApiService,省出时间,全心投入写业务代码 支持SSL自动验证,校验CA证书的有效性与合法性 结合RxJava,处理结果带信号返回

Android 网络编程

详细介绍

awesome-retrofit

基于 Retrofit + RxJava 封装的高效的网络工具,支持 Mock 数据功能

网络结构

功能介绍

  • 支持GET、POST、PUT、DELETE 以及文件上传
  • 支持返回指定的数据结果,默认自动解析为传入的实体类
  • 支持Mock数据可配置化,Mock环境随心切换
  • 支持网络数据缓存可配置化
  • 支持全局网络被踢下线拦截与回调,可自定义错误码
  • 支持泛型自动创建ApiService,省出时间,全心投入写业务代码
  • 支持SSL自动验证,校验CA证书的有效性与合法性

TODO

  • 缓存策略、断线重连机制
  • 页面返回的时候,将网络请求取消
  • 同一个请求多次请求时,短时间忽略相同的请求
  • 同一个请求多次请求时,取消之前发出的请求
  • 发送的请求,多次尝试并确保成功

使用方法

project/build.gradle 添加 Maven 仓库地址
allprojects {
    repositories {
        maven {
            url "http://118.24.177.113:8081/nexus/content/repositories/saic-framework"
        }
    }
}
project/app/build.gradle 依赖中添加引用
dependencies {
    implementation 'com.saic.framework:saic-network:1.0.0'
}

Application中的初始化

class SCApplication extends Application implements SCKickOffDelegate {
    // 网络库初始化
    SCHttpEngine.sharedInstance()
                .baseUrl(BASE_URL)              // 域名,必填
                .setKickOffDelegate(this)       // 全局被踢下线监听
                .cacheEnable(true)              // http-cache开关
                .mockEnable(true)               // mock开关
                .connectTimeout(60)             // 默认15s
                .readTimeout(60)                // 默认15s
                .writeTimeout(60)               // 默认15s
                .cacheSize(20 * 1024 * 1024)    // 缓存大小,默认 10 * 1024 * 1024
                .init(this);

    SCMqttManager.sharedInstance().serverUrl(MQTT_URL_RELEASE)
                // 设置自动重连
                .autoReconnect(true)
                // 设置不清除会话session 可收到服务器之前发出的推送消息
                .cleanSession(false)
                // 唯一标示,可使用默认值
                .clientId("unique id")
                // 心跳包默认的发送间隔
                .keepAliveInterval(20)
                .userName("admin")
                .passWord("password")
                // mqtt连接监听
                .setMqttCallback(this)
                .init(this);
    @Override
    public void onKickOff(String code, String message) {
        // 处理业务端逻辑,如:跳转登录界面
        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
    }
}

Mock文件配置

app/src/main/assets/mock/mockConfig.json
{
  "mockEnabled": 0, // 0:代表全局关闭,1:代表全局打开
  "mockJsonFileList": {
    "/auth/v2/driveractivate": "DriverActivate",
    "/auth/v2/login/driver/mobile": "Login",
    "/driver/v2/cms/conf": "ConfigResource",
    "/driver/v2/work/%s/update": "ModeStatus",
    "/driver/v2/emergencycontact/delete/%s": "EmergencyContact",
    "/driver/v2/auth/uploadfile": "UploadFile"
  }
}

示例:配置登录MockJson文件

app/src/main/assets/mock/Login.json
{
  "mockEnabled": 0, // 0:代表本文件在Mock时关闭,1:代表本文件在Mock时打开
  "mockJson": {
    "data": {
      "accessToken": "",
      "uid": "",
      "realNameCertificated": "",
      "nameMobileBinded": "",
      "registration": "",
      "imToken": ""
    },
    "errCode": 0,
    "errMsg": "OK",
    "now": 1533547808080
  }
}

错误码配置

app/src/main/assets/mock/errorConfig.json
{
  "kickCodes": {
    "-200198": "您尚未登录,请登录",
    "-200199": "您的账号在其他设备登录,请重新登录",
    "310199": "您的账号在其他设备登录,请重新登录"
  },
  "toastCodes": {
    "-400004": "行程状态变更"
  }
}

缓存文件配置

app/src/main/assets/mock/httpCacheConfig.json
{
  "cacheEnable": 1, // 全局缓存开关
  "cacheList": [
    {
      "cacheEnable": 1, // 单个api缓存开关
      "api": "/driver/v2/cms/conf",
      "cacheTime": 60000 //单位:毫秒
    }
  ]
}

HTTP使用示例

        /**
         * 获取指纹(POST 请求示例)
         */
        private void doDriverActivate() {
            String systemVersion = SCDeviceInfo.getSystemVersion();
            RequestFactory.INSTANCE.driverActivate(systemVersion, new SCHttpCallback<R_DriverActivate>() {

                @Override
                public void onResponse(R_DriverActivate x) {
                    SCHeader.sharedInstance().setDeviceFinger(x.getDeviceFinger());
                    tvResponse.setText(x.getDeviceFinger());
                }

                @Override
                public void onFailure(SCApiException apiException) {
                    tvResponse.setText(apiException.getDisplayMessage());
                }
            });
        }

        /**
         * 登录(POST 请求示例)
         */
        private void doLogin() {
            LoginRequest loginRequest = new LoginRequest("18917212395", "888888");
            RequestFactory.INSTANCE.phoneLogin(loginRequest, LoadingDialogAccessory.sharedInstance(), new SCHttpCallback<R_Login>() {
                @Override
                public void onResponse(R_Login x) {
                    SCHeader.sharedInstance().setToken(x.getAccessToken());
                    SCHeader.sharedInstance().setUserId(x.getUid());
                    tvResponse.setText(x.toString());
                }

                @Override
                public void onFailure(SCApiException apiException) {
                    tvResponse.setText(apiException.getDisplayMessage());
                }
            });
        }

        /**
         * 获取公共资源(GET 请求示例)
         */
        private void getCommonResource() {
            RequestFactory.INSTANCE.getCommonResource(LoadingDialogAccessory.sharedInstance(), new SCHttpCallback<R_CommonResource>() {
                @Override
                public void onResponse(R_CommonResource x) {
                    tvResponse.setText(x.toString());
                }

                @Override
                public void onFailure(SCApiException apiException) {
                    tvResponse.setText(apiException.getDisplayMessage());
                }
            });
        }

        /**
         * 司机出车收车切换(PUT 请求示例)
         * status: 状态(0 出车,1 收车)
         */
        private void changeModeStatus() {
            RequestFactory.INSTANCE.changeModeStatus("0", LoadingDialogAccessory.sharedInstance(), new SCHttpCallback<R_ModeStatus>() {
                @Override
                public void onResponse(R_ModeStatus x) {
                    tvResponse.setText(x.toString());
                }

                @Override
                public void onFailure(SCApiException apiException) {
                    tvResponse.setText(apiException.getDisplayMessage());
                }
            });
        }

        /**
         * 删除紧急联系人(DELETE 请求示例)
         * id: 联系人id
         */
        private void deleteContact() {
            RequestFactory.INSTANCE.deleteContact("1", LoadingDialogAccessory.sharedInstance(), new SCHttpCallback<SCBaseResponse>() {
                @Override
                public void onResponse(SCBaseResponse x) {
                    tvResponse.setText(x.showDisplayMessage());
                }

                @Override
                public void onFailure(SCApiException apiException) {
                    tvResponse.setText(apiException.getDisplayMessage());
                }
            });
        }

        /**
         * 上传图片 (UPLOAD 请求示例)
         */
        private void uploadFile() {
            String filePath = SCAppConfig.getWorkFolder() + "WechatIMG385.jpeg";
            RequestFactory.INSTANCE.uploadFile(new File(filePath), null, new SCHttpCallback<R_UploadFile>() {
                @Override
                public void onResponse(R_UploadFile x) {
                    tvResponse.setText(x.getFileId());
                }

                @Override
                public void onFailure(SCApiException apiException) {
                    tvResponse.setText(apiException.getDisplayMessage());
                }

                @Override
                public void onProgress(long progress, long total, boolean done) {

                }
            });
        }

接口组装类示例(FreeMarker自动生成,业务端直接调用)

        /**
         * 设备指纹
         *
         * @param platformVersion 设备号
         * @param httpCallback    返回
         * @return
         */
        public Disposable driverActivate(String platformVersion, SCHttpCallback<R_DriverActivate> httpCallback) {
            SCRequestWrapper requestWrapper = new SCRequestWrapper(AppUrl.DRIVER_ACTIVATE_URL, SCRequestMethod.POST);
            requestWrapper.putParams("platformVersion", platformVersion);
            SCHttpRequest request = new SCHttpRequest();
            return request.sendRequest(requestWrapper, httpCallback)
                    .subscribe();
        }

        /**
         * 登录
         *
         * @param loginRequest 请求参数为实体类
         * @param httpCallback 返回
         * @return
         */
        public Disposable phoneLogin(LoginRequest loginRequest, SCRequestAccessory requestAccessory, SCHttpCallback<R_Login> httpCallback) {
            SCRequestWrapper requestWrapper = new SCRequestWrapper(AppUrl.LOGIN_URL, SCRequestMethod.POST);
            requestWrapper.setRequestEntity(loginRequest);
            SCHttpRequest request = new SCHttpRequest();
            request.addAccessory(requestAccessory);
            return request.sendRequest(requestWrapper, httpCallback)
                    .subscribe();
        }

        /**
         * 获取公共资源
         *
         * @param httpCallback 返回
         * @return
         */
        public Disposable getCommonResource(SCRequestAccessory requestAccessory, SCHttpCallback<R_CommonResource> httpCallback) {
            SCRequestWrapper requestWrapper = new SCRequestWrapper(AppUrl.COMMON_RESOURCE_URL, SCRequestMethod.GET);
            SCHttpRequest request = new SCHttpRequest();
            request.addAccessory(requestAccessory);
            return request.sendRequest(requestWrapper, httpCallback)
                    .subscribe();
        }

        /**
         * 司机出车收车切换
         *
         * @param status       状态(0 出车,1 收车)
         * @param httpCallback 返回
         * @return
         */
        public Disposable changeModeStatus(String status, SCRequestAccessory requestAccessory, SCHttpCallback<R_ModeStatus> httpCallback) {
            String url = String.format(AppUrl.MODE_STATUS_URL, status);
            SCRequestWrapper requestWrapper = new SCRequestWrapper(url, SCRequestMethod.PUT);
            SCHttpRequest request = new SCHttpRequest();
            request.addAccessory(requestAccessory);
            return request.sendRequest(requestWrapper, httpCallback)
                    .subscribe();
        }

        /**
         * 删除联系人
         *
         * @param id           联系人id
         * @param httpCallback 返回
         * @return
         */
        public Disposable deleteContact(String id, SCRequestAccessory requestAccessory, SCHttpCallback<SCBaseResponse> httpCallback) {
            String url = String.format(AppUrl.DELETE_EMERGENCY_CONTACT_URL, id);
            SCRequestWrapper requestWrapper = new SCRequestWrapper(url, SCRequestMethod.DELETE);
            SCHttpRequest request = new SCHttpRequest();
            request.addAccessory(requestAccessory);
            return request.sendRequest(requestWrapper, httpCallback)
                    .subscribe();
        }

        /**
         * 上传文件
         *
         * @param file         上传文件
         * @param httpCallback 返回
         * @return
         */
        public Disposable uploadFile(File file, SCRequestAccessory requestAccessory, SCHttpCallback<R_UploadFile> httpCallback) {
            SCRequestWrapper requestWrapper = new SCRequestWrapper(AppUrl.UPLOAD_FILE_URL, SCRequestMethod.UPLOAD);
            requestWrapper.putMediaType(MediaType.parse(SCRequestWrapper.MEDIA_TYPE_DATA));
            requestWrapper.setUploadFile(file);
            SCHttpRequest request = new SCHttpRequest();
            request.addAccessory(requestAccessory);
            return request.sendRequest(requestWrapper, httpCallback)
                    .subscribe();
        }

MQTT使用示例

        // 连接MQTT
        findViewById(R.id.btn_connect).setOnClickListener(v -> {

            /*********** 普通连接 ***********/
//            SCMqttManager.sharedInstance().connect();

            /*********** 带遗言的连接 ***********/
            String topic = MQTT_INBOUND;
            String json = getPayload("0", "01", driverid);
            byte[] b_payload = json.getBytes();
            int qos = 2;
            boolean retained = false;

            SCMqttManager.sharedInstance().connectWithWill(topic, b_payload, qos, retained);
        });

        // 断开连接
        findViewById(R.id.btn_disconnect).setOnClickListener(v -> {
            SCMqttManager.sharedInstance().disconnect();
        });

        // 订阅
        findViewById(R.id.btn_subscribe).setOnClickListener(v -> {
            String topic = MQTT_OUTBOUND;
            int qos = 2;
            SCMqttManager.sharedInstance().subscribe(topic, qos);
        });

        // 发布
        findViewById(R.id.btn_publish).setOnClickListener(v -> {
            String topic = MQTT_OUTBOUND;
            String json = getPayload("1", "02", driverid);
            byte[] b_payload = json.getBytes();
            int qos = 2;
            SCMqttManager.sharedInstance().publish(topic, qos, b_payload);
        });
        
        private String getPayload(String s, String t, String u) {
            SCMqttMessage message = new SCMqttMessage();
            message.setT("upd");
            SCPayload payload = new SCPayload();
            payload.setS(s); // 0:不可接单, 1:可以接单
            payload.setT(t); // 遗言信息, 01:APP闪退遗言, 02:收车时更改车辆状态
            payload.setU(u);
            message.setPayload(payload);
            return new Gson().toJson(message);
        }