• 「Android」孙正义|窥探OKHttp+Gson


    Json 介绍

    JsonObject 对应Json字符串中用{}包裹的数据,相当于一个实体类
    
    • 1
    JsonArray对应Json字符串中用[]包裹的数据,相当于一个数组
    
    • 1

    下面为从某个服务器中拉去的数据,其中data为数据核心部分,minfo为一个数组,其中包含所需要渲染的数据,filter为一个数据实体,包含筛选条件信息。

    {
        "status":"200",
        "msg
        ":"success",
        "source":"156",
        "data":{
            "data_type":"2",
            "minfo":Array[30],
            "filter":{
                "orderby":[
                    {
                        "title":"Popular",
                        "id":"1"
                    },
                    Object{...},
                    Object{...}
                ],
                "genre":Array[27],
                "pub":Array[12],
                "type":Array[3],
                "country":Array[49]
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    创建对应格式化实体类

    从服务器端拉去的Json字符串,需要创建对应的实体类进行接收,本文介绍一种插件,用于Android端格式化建立实体类

    安装插件GsonFormatPlus

    点击设置->plugins->搜索并安装插件GsonFormatPlus插件

    创建实体类

    第一步,在需要创建实体类的地方右击空白处,在弹出的显示框中选择Generate

    第二步,然后在选择刚才安装的插件GsonFormatPlus

    第三步,最后将Json字符串复制上去,点击OK即可自动创建

    踩坑笔记

    如果你不想一次性创建所有的Json数据对于的实体类,也就是说,你所请求的Json字符串你不想创建在一个实体类中,比如下面Json字符串为例,下面的minfo是一个数组,如果你想把这个数组内的数据单独建立一个实体类,你需要把这个字段定义为JsonArray类型,注意不是全大写,全大写是另外一个类,会出错,JsonObject同理。这样可以让数据更加层次分明,在不同的地方引用时,较为方便。

    private JsonArray orderby;
    
    • 1
    {
        "status":"200",
        "msg
        ":"success",
        "source":"156",
        "data":{
            "data_type":"2",
            "minfo":Array[30],
            "filter":{
                "orderby":[
                    {
                        "title":"Popular",
                        "id":"1"
                    },
                    Object{...},
                    Object{...}
                ],
                "genre":Array[27],
                "pub":Array[12],
                "type":Array[3],
                "country":Array[49]
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Json数据解析

    引入依赖

    implementation 'com.squareup.okhttp3:okhttp:3.1.0'
     implementation 'com.squareup.okio:okio:1.5.0'
     implementation 'com.google.code.gson:gson:2.8.0'
    
    • 1
    • 2
    • 3

    OkHttp封装

    将请求体用map进行键值对进行添加,然后使用表单进行提交。在建立Request对象将请求体进行上传,然后在newCall中接受服务器回调,此类是一个封装类,只取出第一层数据体,因为不同的接口所返回的数据内容不一样,Json体也不一样,所有此处只对第一层进行解析,然后在不同的地方调用时,在进行具体解析。

     /**
         * @param url connect server address
         * @param map request param
         * @param callback bind success or fail callback*/
        public void Post(String url,Map<String,Object> map,HttpCallback callback) {
            OkHttpClient client = new OkHttpClient();
            FormBody.Builder requestBuild = new FormBody.Builder();
            for (Map.Entry<String,Object> mEntry : map.entrySet()) {
                requestBuild.add(mEntry.getKey(),mEntry.getValue()+"");
            }
            RequestBody requestBody = requestBuild.build();
    
            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e("getInternetData","error message = "+e.getMessage());
                    callback.onFailure(ErrorParam.POSTINGERROR);
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String body = response.body().string();
               
                    int code = response.code();
                    if (code == 200){
                        try {
                            JSONObject jsonObject = new JSONObject(body);
                            int status_code = jsonObject.getInt("status");
                            if (status_code == 200){
                                String data = jsonObject.getString("data");
                                callback.onResponse(data);
                            }else {
                                callback.onFailure(ErrorParam.NETWORKERROR);//net error
                            }
                        } catch (JSONException e) {
                            Log.e("getBannerData","error");
                            callback.onFailure(ErrorParam.RESOLVINGERROR);//resolve error
                            e.printStackTrace();
                        }
                    }else {
                        callback.onFailure(ErrorParam.SERVERERROR);//service error
                    }
                }
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    JsonObject解析

      * resolve jsonboject*/
        public static <T> T fromJson(String josn,Class<T> c){
            Gson gson = new Gson();
            T t = null;
            return t = gson.fromJson(josn,c);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    JsonArray解析

    public static <T> List<T> fromListJson(String json,Class<T> c){
            List<T> list  = new ArrayList<>();
                Gson gson = new Gson();
                JsonArray array = new JsonParser().parse(json).getAsJsonArray();
                for (final JsonElement element: array) {
                    list.add(gson.fromJson(element,c));
                }
            return list;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    回调

    建立一个回调接口,将解析结果暴露给外部

    public interface HttpCallback<T> {
    
        void onFailure(int error);
    
        void onResponse(T data) throws JSONException;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    完整封装

    因为隐私,服务器接口和请求体暂不外露,其余内容如下所示

    public class OKHttpUtils {
        private static Map<String,Object> map = new HashMap<>();
        private static OKHttpUtils singleton;
        private OKHttpUtils(){
    
        }
        public static  OKHttpUtils getInstance(){
            if (singleton == null){
                Sync();
            }
            return singleton;
        }
        private static synchronized void Sync(){
            if (singleton == null){
                singleton = new OKHttpUtils();
                InitMap();
            }
        }
        /**
         * @param url connect server address
         * @param map request param
         * @param callback bind success or fail callback*/
        public void Post(String url,Map<String,Object> map,HttpCallback callback) {
            OkHttpClient client = new OkHttpClient();
            FormBody.Builder requestBuild = new FormBody.Builder();
            for (Map.Entry<String,Object> mEntry : map.entrySet()) {
                requestBuild.add(mEntry.getKey(),mEntry.getValue()+"");
            }
            RequestBody requestBody = requestBuild.build();
    
            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e("getInternetData","error message = "+e.getMessage());
                    callback.onFailure(ErrorParam.POSTINGERROR);
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String body = response.body().string();
                    Log.d("sss",body.toString());
                    int code = response.code();
                    if (code == 200){
                        try {
                            JSONObject jsonObject = new JSONObject(body);
                            int status_code = jsonObject.getInt("status");
                            if (status_code == 200){
                                String data = jsonObject.getString("data");
                                callback.onResponse(data);
                            }else {
                                callback.onFailure(ErrorParam.NETWORKERROR);//net error
                            }
                        } catch (JSONException e) {
                            Log.e("getBannerData","error");
                            callback.onFailure(ErrorParam.RESOLVINGERROR);//resolve error
                            e.printStackTrace();
                        }
                    }else {
                        callback.onFailure(ErrorParam.SERVERERROR);//service error
                    }
                }
            });
        }
    
        /**
         * public request param*/
        private static void InitMap(){
      //因为隐私,请求体省略
        }
    
        public Map<String,Object> getMap(){
            return map;
        }
        public String setUrl(String port){
            return PortParam.BaseUrl+port;
        }
        /**
         * resolve jsonboject*/
        public static <T> T fromJson(String josn,Class<T> c){
            Gson gson = new Gson();
            T t = null;
            return t = gson.fromJson(josn,c);
        }
        /**
         * resolve jsonarray*/
        public static <T> List<T> fromListJson(String json,Class<T> c){
            List<T> list  = new ArrayList<>();
                Gson gson = new Gson();
                JsonArray array = new JsonParser().parse(json).getAsJsonArray();
                for (final JsonElement element: array) {
                    list.add(gson.fromJson(element,c));
                }
            return list;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    Json解析

    然后在外部进行服务器地址、请求体上传,在进行进一步解析,在下面通过刚刚建立的回调接口,在OnFailure()中进行错误解析回调,并处理;在OnResponse()中进行json字符串获取,此字符串已经被解析了一层,在根据不同的接口回调,做出不同响应即可,此处将获取的json字符串转为数组形式。

    private void Post(){
            OKHttpUtils utils = OKHttpUtils.getInstance();
            Map<String,Object> map = utils.getMap();
           //内容省略...map.put("","");
            utils.Post(utils.setUrl(PortParam.TvShowsPort), map, new HttpCallback() {
                @Override
                public void onFailure(int error) {
                    switch (error){
                        case ErrorParam.NETWORKERROR:
                            break;
                        case ErrorParam.SERVERERROR:
                            break;
                        case ErrorParam.RESOLVINGERROR:
                            break;
                        case ErrorParam.POSTINGERROR:
                            handler.sendEmptyMessage(4);
                                break;
                    }
                }
    
                @Override
                public void onResponse(Object data) throws JSONException {
                    array = new JSONArray(data.toString());
                    handler.sendEmptyMessage(0);
                }
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    然后使用rxjava进行监听,此框架一目了然,subscribe()建立被观察者,subscribe()建立观察者,然后onNext()、onComplete(),此处回调的数据较多,又分为不同的场景,头部有一个轮播图baner数据,下面有一个RecyclerView嵌套RecyclerView,需要根据判断解析的Display_type判断其显示方式,从而决定RecyclerView是横向显示还是竖向显示。最后通过handler异步渲染UI。

    private void UpdateUI(){
            Observable.create(new ObservableOnSubscribe<FeaturedData>() {
                @Override
                public void subscribe(@NotNull ObservableEmitter<FeaturedData> observableEmitter) throws Exception {
                    if (featuredDataList != null){
                        for (int i = 0; i < featuredDataList.size(); i++) {
                            if (featuredDataList.get(i).getData_type().equals("1")){
                                observableEmitter.onNext(featuredDataList.get(i));
                            }
                        }
                        observableEmitter.onComplete();
                    }
    
                }
            }).subscribe(new Observer<FeaturedData>() {
                @Override
                public void onSubscribe(@NotNull Disposable disposable) {
    
                }
    
                @Override
                public void onNext(@NotNull FeaturedData featuredData) {
                    if (featuredData.getName().equals("Banner")){
                        try {
                            JSONArray array = new JSONArray(featuredData.getData().toString());
                            featureBannerDataList = OKHttpUtils.fromListJson(array.toString(),FeatureBannerData.class);
                           //update banner
                            handler.sendEmptyMessage(2);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }else if (featuredData.getDisplay_type().equals("1")){
                    //v
                        JSONArray jsonArray = null;
                        JSONObject object = null;
                        try {
                            jsonArray = new JSONArray(featuredData.getData().toString());
                            object = jsonArray.getJSONObject(0);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        FeatureInnerData data = OKHttpUtils.fromJson(object.toString(),FeatureInnerData.class);
                        data.setSlide_way(1);
                        featureInnerDataList.add(data);
                    }else {
                        //H
                        JSONArray jsonArray = null;
                        JSONObject object = null;
                        try {
                            jsonArray = new JSONArray(featuredData.getData().toString());
                            object = jsonArray.getJSONObject(0);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        FeatureInnerData data = OKHttpUtils.fromJson(object.toString(),FeatureInnerData.class);
                        data.setSlide_way(2);
                        featureInnerDataList.add(data);
                    }
                }
    
                @Override
                public void onError(@NotNull Throwable throwable) {
    
                }
    
                @Override
                public void onComplete() {
                    handler.sendEmptyMessage(3);
    
                }
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
  • 相关阅读:
    SpringCloud全系列知识(2)—— Nacos配置和集群
    P6775 [NOI2020] 制作菜品
    Linux常用命令
    使用UEFI固件引导KVM虚拟机
    一文读懂WebClient和RestTemplate的差异
    mysql锁
    金仓数据库KingbaseES客户端编程接口指南-Python(2. 概述)
    【定义】矩阵
    夯实算法-课程表
    SOLIDWORKS焊件使用教程
  • 原文地址:https://blog.csdn.net/News53231323/article/details/125350090