企业级app组件化开发1-----网络请求组件开发

1、沉浸式布局

在AndroidMainfest清单文件中,默认设置的AppTheme就是3种颜色值,因此状态栏的颜色就是默认的颜色,如果想要改变其中的颜色,那么就需要自定义style;

API 19以上,需要设置android:windowTranslucentStatus为false,否则系统还是会默认将状态栏设置为绿色;
从Android5.x开始,也就是API 21以上,需要将android:statusBarColor设置为透明,然后再设置一下属性,这样就能实现沉浸式布局。

<style name="StatusBarTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!--沉浸式状态栏-->
        <!--API > 19 需要设置这个属性-->
        <item name="android:windowTranslucentStatus">false</item>

        <!--Android 5.x开始把颜色设置为透明,否则会默认赋值-->
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:navigationBarColor">@android:color/white</item>
        <item name="android:fitsSystemWindows">true</item>
        <!--允许Activity的转场动画-->
        <item name="android:windowActivityTransitions">true</item>
    </style>

在这里插入图片描述
2、网络请求组件开发

导入OkHttp的依赖,做二次封装,主要从RequestOkHttpClientResponse3部分做Base封装。

implementation 'com.squareup.okio:okio:2.6.0'
implementation 'com.squareup.okhttp3:okhttp:4.7.0'

(1)Request

请求的种类主要分为如下几种:get、post、文件上传,因此封装一个通用 的请求类,供应用层使用。

对于get请求和post请求来说,在使用的时候,需要自己创建请求Request,对于get请求方式来说,请求体是跟url拼接在一起的,暴露在url中的,而post请求的请求头和请求体是分开的。

/**
 * 对外提供get/post/文件上传等请求
 */
public class CommRequest {

    /**
     * 创建post请求
     * @param url  Http的url地址
     * @param header  请求头
     * @param body 请求体
     * @return
     */
    public static Request createPostRequest(String url, RequestParams header, RequestParams body){
        //请求体(表单格式)
        FormBody.Builder formBody = new FormBody.Builder();
        if(body != null){
            for(Map.Entry<String,String> entry : body.urlParams.entrySet()){
                formBody.add(entry.getKey(),entry.getValue());
            }
        }
        //请求头
        Headers.Builder headers = new Headers.Builder();
        if(header != null){
            for(Map.Entry<String,String> entry : header.urlParams.entrySet()){
                headers.add(entry.getKey(),entry.getValue());
            }
        }
        //创建请求
        Request request = new Request.Builder()
                .url(url).headers(headers.build())
                .post(formBody.build())
                .build();
        return request;
    }

    /**
     * 重载的创建post请求(没有请求头)
     * @param url  post请求的url地址
     * @param params  请求体
     * @return
     */
    public static Request createPostRequest(String url,RequestParams params){
        return createPostRequest(url,null,params);
    }

    /**
     * 创建get请求
     * @param url  get请求的url地址
     * @param params  请求体
     * @param header  请求头
     * @return
     */
    public static Request createGetRequest(String url,RequestParams params,RequestParams header){
        StringBuilder getUrl = new StringBuilder(url).append("?");
        if(params != null){
            for(Map.Entry<String,String> entry : params.urlParams.entrySet()){
                getUrl.append(entry.getKey()).append("=").append(entry.getValue());
            }
        }
        //请求头
        Headers.Builder headers = new Headers.Builder();
        if(header != null){
            for(Map.Entry<String,String> entry : header.urlParams.entrySet()){
                headers.add(entry.getKey(),entry.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .headers(headers.build())
                //可不写,默认是get请求
                .get()
                .build();
        return request;
    }

    /**
     * 重载get请求,没有请求头
     * @param url  请求的url地址
     * @param params  请求的参数
     * @return
     */
    public static Request createGetRequest(String url,RequestParams params){
        return createGetRequest(url,params);
    }
}

对于文件上传,常常使用post请求方式,对于多媒体类型的文件,需要设置Content-type或者叫做MediaType,常见的Content-type有:

多媒体类型名称
text/htmlHTML格式
text/pain纯文本格式
image/jpegJPEG图片格式
application/jsonJSON格式数据
application/octet-stream二进制流数据(文件下载)
application/x-www-form-urlencoded表单数据以kay/value形式发送到服务器
multipart/form-data表单上传文件格式
 /**
     * 上传多媒体数据(文件)
     * @param url 
     * @param params  请求体
     * @param header  
     * @return
     */
    public static Request createMutiPostRequest(String url,RequestParams params,RequestParams header){
        MultipartBody.Builder partBuilder = new MultipartBody.Builder();
        //设置表单格式上传
        partBuilder.setType(MultipartBody.FORM);
        if(params != null){
            for(Map.Entry<String,Object> entry : params.fileParams.entrySet()){
                if(entry.getValue() instanceof File){
                    partBuilder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + entry.getKey() + "\""),
                            RequestBody.create((File) entry.getValue(),FILE_TYPE));
                }
            }
        }
        //请求头
        Headers.Builder headers = new Headers.Builder();
        if(header != null){
            for(Map.Entry<String,String> entry : header.urlParams.entrySet()){
                headers.add(entry.getKey(),entry.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .headers(headers.build())
                .post(partBuilder.build())
                .build();
        return request;
    }

(2)Response

请求的获取的响应,往往是JSON字符串,因此需要对获取到的JSON字符串进行解析。

/**
 * 通用的JSON数据Callback回调
 */
public class CommJsonCallback implements Callback {

    //网络异常
    private static final int NETWORK_ERROR = -1;
    //Json数据异常
    private static final int JSON_ERROR = -2;
    //其他异常
    private static final int OTHER_ERROR = -3;

    //响应分发
    private DisposeDataListener mListener;
    //线程切换
    private Handler mDeliveryHandler;

    //Json数据转换为Class实体类
    private Class<?> classBean;

    public CommJsonCallback(DisposeDataHandle handle){
        mListener = handle.mListener;
        classBean = handle.mClass;
        mDeliveryHandler = new Handler(Looper.getMainLooper());
    }

    @Override
    public void onFailure(@NotNull Call call, @NotNull final IOException e) {
        //处理响应失败的回调
        mDeliveryHandler.post(new Runnable() {
            @Override
            public void run() {
                mListener.onFailed(new OkHttpException(NETWORK_ERROR,e));
            }
        });
    }

    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
        //拿到响应的JSON数据
        final String result = response.body().string();
        mDeliveryHandler.post(new Runnable() {
            @Override
            public void run() {
                //JSON数据解析
                parseResponse(result);
            }
        });

    }

    private void parseResponse(String result) {
        if(result == null || result.trim().equals("")){
            mListener.onFailed(new OkHttpException(JSON_ERROR,"JSON数据错误"));
            return;
        }
        if(classBean == null){
            //业务层不需要解析JSON数据,直接返回JSON字符串
            mListener.onSuccess(result);
        }else{
            //解析JSON数据
            Gson gson = new Gson();
            Object obj = gson.fromJson(result, classBean);
            if(obj != null){
                //解析成功,返回主线程
                mListener.onSuccess(obj);
            }else{
                mListener.onFailed(new OkHttpException(JSON_ERROR,""));
            }
        }
    }
}

也包括文件数据等多媒体响应,文件通常使用IO流解析。

public class CommFileCallback implements Callback {

    //网络错误
    private static final int NETWORK_ERROR = -1;
    //IO错误
    private static final int IO_ERROR = -2;
    //错误信息
    private String EMPTY_MSG = "";

    private static final int FILE_PROGRESS = 0x01;
    //真正处理回调的接口
    private DisposeFileListener mListener;
    //线程切换的Handler
    private Handler mDeliveryHandler;

    //下载文件的进度和路径
    private String filePath;
    private int mProgress;

    public CommFileCallback(DisposeDataHandle handle){
        this.mListener = (DisposeFileListener) handle.mListener;
        this.filePath = handle.mSource;
        this.mDeliveryHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(@NonNull Message msg) {
                switch (msg.what){
                    case FILE_PROGRESS:
                        //回调当前的进度
                        mListener.onProgress((Integer) msg.obj);
                        break;
                }
            }
        };
    }
    @Override
    public void onFailure(@NotNull Call call, @NotNull IOException e) {
        mDeliveryHandler.post(new Runnable() {
            @Override
            public void run() {
                mListener.onFailed(new OkHttpException(NETWORK_ERROR,EMPTY_MSG));
            }
        });
    }

    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
        final File file = handleResponse(response);
        mDeliveryHandler.post(new Runnable() {
            @Override
            public void run() {
                if(file != null){
                    mListener.onSuccess(file);
                }else{
                    mListener.onFailed(new OkHttpException(IO_ERROR,EMPTY_MSG));
                }
            }
        });
    }

    /**
     * 通过文件流来读写文件
     * @param response
     * @return
     */
    private File handleResponse(Response response) {

        InputStream is = null;
        FileOutputStream fos = null;
        int length;
        int currentLength = 0;
        int sumLength;
        byte[] bytes = new byte[2048];
        //读取输入流
        try{
            //创建文件
            File file = new File(filePath);
            if(!file.exists()){
                file.mkdir();
            }

            is = response.body().byteStream();
            fos = new FileOutputStream(file);

            while((length = is.read(bytes) ) != -1){
                fos.write(bytes,0,bytes.length);
                //当前下载的进度
                currentLength += length;
                //总进度
                sumLength = (int) (currentLength / response.body().contentLength() *100);
                //将进度值发布
                mDeliveryHandler.obtainMessage(FILE_PROGRESS,sumLength).sendToTarget();
            }
            fos.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                fos.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        return null;
    }
}

对于两类的响应处理方式,有很多重复的代码,因此可以创建一个抽象基类,避免重复的代码。

public abstract class BaseCallback implements Callback {

    //网络异常
    private static final int NETWORK_ERROR = -1;
    //Json数据异常
    protected static final int JSON_ERROR = -2;
    //其他异常
    private static final int OTHER_ERROR = -3;
    //IO错误
    private static final int IO_ERROR = -4;
    //错误信息
    protected String EMPTY_MSG = "";

    //真正处理逻辑的监听接口
    protected DisposeDataListener mListener;
    //handler线程切换
    protected Handler mDeliveryHandler;
    private static final int FILE_PROGRESS = 0x01;

    //下载文件的进度和路径
    private String filePath;
    private int mProgress;


    public BaseCallback(DisposeDataHandle handle){
        this.mListener = getListener(handle);
        mDeliveryHandler = new Handler(Looper.getMainLooper());
    }

    protected abstract DisposeDataListener getListener(DisposeDataHandle handle);

    @Override
    public void onFailure(@NotNull Call call, @NotNull IOException e) {
        //发生网络错误
        mDeliveryHandler.post(new Runnable() {
            @Override
            public void run() {
                mListener.onFailed(new OkHttpException(NETWORK_ERROR,EMPTY_MSG));
            }
        });
    }

    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
        //数据解析,这个部分需要抽象解析
        handleResponse(response);
    }

    protected abstract void handleResponse(Response response);
}

对于子类的实现类,就拿JSON响应来举例子

public class JsonCallback extends BaseCallback {
    //Json数据转换为Class实体类
    private Class<?> classBean;

    public JsonCallback(DisposeDataHandle handle) {
        super(handle);
        this.classBean = handle.mClass;
    }

    @Override
    protected DisposeDataListener getListener(DisposeDataHandle handle) {
        return handle.mListener;
    }

    @Override
    protected void handleResponse(Response response) {
        //解析响应数据
        try {
            final String result = response.body().string();
            mDeliveryHandler.post(new Runnable() {
                @Override
                public void run() {
                    //JSON数据解析
                    parseResponse(result);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void parseResponse(String result) {
        if (result == null || result.trim().equals("")) {
            mListener.onFailed(new OkHttpException(JSON_ERROR, "JSON数据错误"));
            return;
        }
        if (classBean == null) {
            //业务层不需要解析JSON数据,直接返回JSON字符串
            mListener.onSuccess(result);
        } else {
            //解析JSON数据
            Gson gson = new Gson();
            Object obj = gson.fromJson(result, classBean);
            if (obj != null) {
                //解析成功,返回主线程
                mListener.onSuccess(obj);
            } else {
                mListener.onFailed(new OkHttpException(JSON_ERROR, ""));
            }
        }
    }
}

因为JSON需要解析实体类,因此需要在构造方法中,添加一个形参,这就是抽象的概念,对于子类来说,在继承父类的构造方法中,可以添加新的参数,作为子类的构造方法。

然后创建一个监听器,子类的监听器,视情况而定,最重要的就是解析数据,这个对于每一个子类,都需要自己实现。

(3)OkHttpClient

在使用OkHttpClient的时候,首先需要初始化,一般有以下几种处理:

//host域名验证,验证客户端请求的url是否和服务端一致,防止中间人攻击
        clientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });

添加域名验证,此举是为了防止第三方攻击服务器。

当使用Https协议的时候,通常服务器会将证书信息(包含公钥)发送给客户端,客户端将生成数据传输的公钥,通过服务器端的公钥加密,发送到服务器使用私钥解密,这个过程其实是不安全的。

当服务器发送的公钥被第三方获取,将假公钥给到客户端,客户端加密后被第三方获取,将数据传输的公钥修改后,使用公钥加密给到服务器,这样双方对称加密的公钥就是被窃取,这样非常不安全。

所以客户端需要验证,证书是否来自服务器,也就是说CA证书所在服务器的host域名和请求的host域名是否一致,如果不一致那么就会回调hostnameVerifier这个接口,验证主机名host。

/**
 * 公共的OkHttpClient
 */
public class CommOkHttpClient {

    //连接超时
    private static final int TIME_OUT = 30;
    //OkHttp对象
    public static OkHttpClient okHttpClient;
    //初始化OkHttpClient对象
    static {
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        //host域名验证,验证客户端请求的url是否和服务端一致,防止中间人攻击
        clientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        //添加请求头
        clientBuilder.addInterceptor(new Interceptor() {
            @NotNull
            @Override
            public Response intercept(@NotNull Chain chain) throws IOException {
                Request request = chain.request().newBuilder().
                        addHeader("User-Agent", "Imooc-Mobile").build();
                return chain.proceed(request);
            }
        });
        //设置超时
        clientBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
        clientBuilder.readTimeout(TIME_OUT, TimeUnit.SECONDS);
        clientBuilder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);
        //允许重定向
        clientBuilder.followRedirects(true);
        //创建OkHttpClient对象
        okHttpClient = clientBuilder.build();
    }

    //创建get请求
    public static Call get(Request request, DisposeDataHandle handle){
        Call call = okHttpClient.newCall(request);
        call.enqueue(new CommJsonCallback(handle));
        return call;
    }

    //创建post请求
    public static Call post(Request request, DisposeDataHandle handle){
        Call call = okHttpClient.newCall(request);
        call.enqueue(new CommJsonCallback(handle));
        return call;
    }

    //创建get请求
    public static Call downLoadFile(Request request, DisposeDataHandle handle){
        Call call = okHttpClient.newCall(request);
        call.enqueue(new CommFileCallback(handle));
        return call;
    }
}

在使用时,既可以简化api结构

 public static void postRequest(String url, RequestParams params,
                                   DisposeDataListener listener,Class<?> aClass){

        CommOkHttpClient.post(CommRequest.createPostRequest(url,params),
                new DisposeDataHandle(listener,aClass));
    }

    public static void LoginRequest(DisposeDataListener listener,Class<?> aClass){
        RequestParams params = new RequestParams();
        params.put("admin","123456");
        postRequest(HttpConstants.LOGIN,params,listener,aClass);
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Awesome_lay

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

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

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

打赏作者

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

抵扣说明:

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

余额充值