Android开发JSONObject的使用

什么是JSON

1、JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
2、JSON 是轻量级的文本数据交换格式
3、JSON 独立于语言 (单纯的数据格式,不受语言的约束)
4、JSON 具有自我描述性,更易理解

从官网描述可以看出,JSON本身是JavaScript中对象的描述格式,后来得以推广并慢慢取代xml。

JSON和XML的比较

相比 XML 的不同之处

1、没有结束标签(类似于键值对的形式)
2、更短(没有结束标签,当然短了)
3、读写的速度更快
4、能够使用内建的 JavaScript eval() 方法进行解析
5、使用数组
6、不使用保留字

原生JSON解析

Android原生的解析实际上使用的是JSON的一个官方jar包。
在使用之前我们需要下载org.json的jar包。对于Android 开发环境不需要下载此jar包。因为Android SDK 中已经默认包含了该jar包。
json jar 下载地址
下载完之后导入即可。

JSONObject对象解析

下面看一下数据

{
    "user":{
        "name":"alex",
        "age":"18",
        "isMan":true
    }
}

有一个user字段,其中包含了该user的一些基本属性。那么如何解析呢?
在解析时,有一个很关键的地方:如果是{}包含,则为JSONObject对象,如果为[]则为JSONArray对象。
看到上面的例子,我们看到整个数据为JSONObject,其内部包含了一个user字段,该字段的值也是一个JSONObject对象。

public class OrgJSONTest {
    public static String json = "{\"user\":{\"name\":\"alex\",\"age\":\"18\",\"isMan\":true}}";

    public static void main(String[] args){
        JSONObject obj = new JSONObject(json);//最外层的JSONObject对象
        JSONObject user = obj.getJSONObject("user");//通过user字段获取其所包含的JSONObject对象
        String name = user.getString("name");//通过name字段获取其所包含的字符串
        System.out.println(name);
    }
}

打印结果如下
<alex
可以看到获取到了相应的值。
在JSONObject对象中封装了getXXX()等一系列方法。用以获取字符串,整形等等一系列的值。

对于如上例子,完全解析user对象如下

String name = user.getString("name");//通过name字段获取其所包含的字符串
String age = user.getString("age");
boolean isMan = user.getBoolean("isMan");
System.out.println("name:"+name+"\nage:"+age+"\nisMan:"+isMan);

结果如下
<name:alex
age:18
isMan:true
这种通过getXXX的方式,无疑会出现一些问题,我们开始一一尝试。

getXXX方法获取的类型不符

1、字符串类型转整形

对于上面的例子,我们可以看到age字段虽然其对应的值是双引号括起的字符串,但其实际上是一个整形,那么我们是否能够通过getInt获取整形呢

int age = user.getInt("age");

当然是可以得,同时字符串类型可以转化为布尔类型,整数类型,浮点型等等。但字符串的内容必须符合规范,否则会报异常。如果看其源码可知,其内部实质是调用了对应对象的parseXXX()方法进行转化操作。

    //getInt源码
  public int getInt(String key) throws JSONException {
        Object object = this.get(key);
 
        try {
            //关键点,如果是数值类型,则调用intValue(),否则强转成字符串之后调用parserInt方法()
            return object instanceof Number?((Num,ber)object).intValue():Integer.parseInt((String)object);
        } catch (Exception var4) {
            throw new JSONException("JSONObject[" + quote(key) + "] is not an int.");
        }
    }

2、整形等转字符串类型
按照如上的思维逻辑,直接getString("xxx")就可以了。但事实正好相反,该方法,如果对应值不是双引号括起的,则会抛出异常。

 //getString 源码
 public String getString(String key) throws JSONException {
        Object object = this.get(key);
        //直接判断是否是字符串类型,如果不是,则抛出异常
        if(object instanceof String) {
            return (String)object;
        } else {
            throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
        }
    }

getXXX(“”) 没有对应的键值
通过上面的例子,可以得知getXXX("")方法是通过字段(键)获取对应的值。那么肯定存在一种情况,及没有键的存在。

System.out.println(user.getString("sex"));
报错:
Exception in thread "main" org.json.JSONException: JSONObject["sex"] not found.
    at org.json.JSONObject.get(JSONObject.java:471)
    at org.json.JSONObject.getString(JSONObject.java:717)
    at json.OrgJSONTest.main(OrgJSONTest.java:24)

果断报异常。

那么怎么办呢:使用optXXX()。

这里简单讲解了JSONObject解析字符串,下面具体举一个例子:
Android App 接受服务端通知是非常常见的业务逻辑,比如微信公众号消息推送,推文推送,或者接受聊天信息等

现在有一个业务,需要在App端实时监听订单的状态,这里我使用mqtt协议来时时获取服务端最新的消息
MQ服务消息到达回调方法

@Override
        public void messageArrived(String topic, final MqttMessage message) throws Exception {
            try{
                // 读取本地保存用户的登录信息
                SharedPreferences sp = getSharedPreferences("token_data", Context.MODE_PRIVATE);
                String token = sp.getString("token","");
                if(TextUtils.isEmpty(token)){
                    return;
                }
                String msg = new String(message.getPayload());
                Gson gson = new Gson();
                JSONObject jsonObject = new JSONObject(msg);
            
                JSONObject taskList = (JSONObject)jsonObject.get("agv_task_list");
                Map<String, ArrayList<StockTaskBean>> map = new HashMap<>();
                Iterator<String> taskKeysIterator = taskList.keys();
                while (taskKeysIterator.hasNext()) {
                    String next = taskKeysIterator.next();
                    ArrayList<StockTaskBean> beans = new ArrayList<>();
                    JSONArray array = taskList.getJSONArray(next);
                    for (int i=0; i<array.length(); i++){
                        JSONObject object = array.getJSONObject(i);//遍历得到数组中的各个对象
                        StockTaskBean bean = gson.fromJson(object.toString(), StockTaskBean.class);
                        beans.add(bean);
                    }
                    map.put(next,beans);
                }
                ArrayList<StockTaskBean> beans = map.get(token);
                if(beans != null){
                    intentAgvTaskListBroadcast.putExtra("agv_task_list",beans);
                    sendBroadcast(intentAgvTaskListBroadcast);
                }


                JSONObject freeShelList = (JSONObject)jsonObject.get("freeShelfPoint");
                ArrayList<SpinnerBean> freeShelBeans = new ArrayList<>();
                Iterator<String> freeShelfIterator = freeShelList.keys();
                while (freeShelfIterator.hasNext()) {
                    String next = freeShelfIterator.next();
                    String value = freeShelList.getString(next);
                    SpinnerBean bean = new SpinnerBean(next,value);
                    freeShelBeans.add(bean);
                }

                intentAgvShelfPointBroadcast.putExtra("freeShelfPoint",freeShelBeans);
                sendBroadcast(intentAgvShelfPointBroadcast);
            }catch (Exception e){
                Log.d(TAG, "消息到达处理异常:"+e.getMessage());
            }
        }

接收到服务端的json消息格式如下:

{
    "freeShelfPoint": {
        "10101020": "f03fb1e9de19422cb9ec82b9cd37a1c8"
    }, 
    "agv_task_list": {
        "9bdfbae87f4441d4b0176ee042dc3cd4": [
            {
                "taskId": "a46f3c66d28b48c78996a4290138db00", 
                "taskState": "3", 
                "taskCode": "20230616384163", 
                "taskOrder": "10000468259", 
                "taskBatch": "CO2300732", 
                "line": "包装-1线", 
                "shelfPoint": "10701175", 
                "stockPoint": "09901065,09601065", 
                "transferPoint": "10101315", 
                "callPoint": "", 
                "releasePoint": "", 
                "productTime": "2023-06-14", 
                "carposition": ""
            }, 
            {
                "taskId": "d16c17859b2143b58c427f478b14fcf4", 
                "taskState": "3", 
                "taskCode": "20230616881205", 
                "taskOrder": "10000468259", 
                "taskBatch": "CO2300732", 
                "line": "包装-1线", 
                "shelfPoint": "10701270", 
                "stockPoint": "09501065", 
                "transferPoint": "10101220", 
                "callPoint": "", 
                "releasePoint": "", 
                "productTime": "2023-06-14", 
                "carposition": ""
            }, 
            {
                "taskId": "f871ab15a847442bbbb82809d2268198", 
                "taskState": "0", 
                "taskCode": "202306168857", 
                "taskOrder": "10000468259", 
                "taskBatch": "CO2300732", 
                "line": "包装-1线", 
                "shelfPoint": "10701515", 
                "stockPoint": "09301065", 
                "transferPoint": "", 
                "callPoint": "", 
                "releasePoint": "", 
                "productTime": "2023-06-14", 
                "carposition": ""
            }
        ], 
        "ac7e0361a712474cb18b9e4913f0d1c2": [
            {
                "taskId": "ee0e282895fe4963b556dc096190b0c2", 
                "taskState": "1", 
                "taskCode": "20230615669165", 
                "taskOrder": "10000468259", 
                "taskBatch": "CO2300732", 
                "line": "包装-1线", 
                "shelfPoint": "10701360", 
                "stockPoint": "09901420", 
                "transferPoint": "", 
                "callPoint": "", 
                "releasePoint": "", 
                "productTime": "2023-06-13", 
                "carposition": ""
            }
        ]
    }
}

因为接受的是字符串,所以直接将字符串作为参数传入JSONObject构造函数实例化一个JSONObject对象

JSONObject jsonObject = new JSONObject(msg);

接下去就是对jsonObject 进行操作
可以看到上面的json消息分为两部分

freeShelfPoint的key/value都是字符串,这很简单,使用freeShelList.keys()生成一个key的迭代器,然后遍历每个key获取对应的value转换成对象,保存在集合中

JSONObject freeShelList = (JSONObject)jsonObject.get("freeShelfPoint");
                ArrayList<SpinnerBean> freeShelBeans = new ArrayList<>();
                Iterator<String> freeShelfIterator = freeShelList.keys();
                while (freeShelfIterator.hasNext()) {
                    String next = freeShelfIterator.next();
                    String value = freeShelList.getString(next);
                    SpinnerBean bean = new SpinnerBean(next,value);
                    freeShelBeans.add(bean);
                }

agv_task_list的值中,key/value变成 字符串/集合的方式,就要多处理一下
jsonObject.get("agv_task_list")获取到agv_task_list里面jsonObject对象,和上面一样生成key的迭代器,遍历每个key获取对应的value,这里的value是数组自然就要使用 getJSONArray(key)的方式获取到 JSONArray array 对象,for循环遍历JSONArray 后利用Gson的fromJson(String json, Class<T> classOfT)方法直接将json对象转换成Javabean对象。

OK 以上就是我的一些分享~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容