上篇博客,我们谈到了XML两种常用的解析技术,详细可以参见我的博客(android基础---->XMl数据的解析)。网络传输另外一种数据格式JSON就是我们今天要讲的,它是比XML体积更小的数据格式,在网络上传输的时候可以更省流量。JSON解析的框架有很多,我们就讲使用JSONObjectGson两种,好了我们开始Json的讲解。

 

目录导航:

  1.  JSONObject常见的使用
  2.  JSONObject的实现原理
  3.  Gson常见的使用
  4.  JSON的使用实例
  5.  友情链接

 

JSONObject的使用

 一、 JSON对象的使用:

String content = "{'username': 'linux', 'password': '123456'}";
JSONObject jsonObject = new JSONObject(content);
String username = jsonObject.getString("username");
String password = jsonObject.getString("password");

 

二、 JSON数组的使用:

复制代码
String jsonContent = "[{'user': '刘力', 'age': 21, 'femal': true}, "
                        + "{'user': 'chen', 'age': 20, 'femal': false}]";
JSONArray jsonArray = new JSONArray(jsonContent);
for (int i = 0; i < jsonArray.length(); i++) {
      JSONObject object = jsonArray.getJSONObject(i);
      System.out.print(object.getString("user") + " ");
      System.out.print(object.getInt("age") + " ");
      System.out.print(object.getBoolean("femal") + " ");
      System.out.println();
}
复制代码

 

三、 JSON数组与JSON对象混合使用

复制代码
String jsonString = "[{'user': 'tomhu', 'age': 21, " + "'info': {'adress': 'hubai', 'sex': 'femal'}}, "
                    + "{'user': 'chen', 'age': 20, " + "'info': {'adress': 'hunan', 'sex': 'male'}}]";
JSONArray jsonArrays = new JSONArray(jsonString);
for (int i = 0; i < jsonArrays.length(); i++) {
    JSONObject objects = jsonArrays.getJSONObject(i);
    System.out.print(objects.getString("user") + " ");
    System.out.print(objects.getInt("age") + " ");
    System.out.print(objects.getJSONObject("info").getString("adress") + " ");
    System.out.print(objects.getJSONObject("info").getString("sex") + " ");
    System.out.println();
}
复制代码

 

四、 JSON数组中存储对象

复制代码
Person person = new Person();
person.setUsername("linux" );
person.setPassword("123456" );
JSONArray jsonArray = new JSONArray();
jsonArray.put(0, person );
jsonArray.put(1, "I love you" );

// String username = jsonArray.getJSONObject(0).getString("username");  错误的写法
Person user = (Person) jsonArray.get(0);
System.out.println("username: " + user.getUsername());
复制代码

 

JSONObject的原理

JsonObject的存储与取出

一、 JSONObject里面维护了一个LinkedHashMap,当生成一个无参数的JSONObject,实质是初始化了一个Map

private final LinkedHashMap<String, Object> nameValuePairs;
public JSONObject() {
    nameValuePairs = new LinkedHashMap<String, Object>();
}

 

 二、 当JSONObject增加数据,实质上把数据的键值对方法存放在上述的Map中:

public JSONObject put(String name, boolean value) throws JSONException {
    nameValuePairs.put(checkName(name), value);
    return this;
}

 

三、 从JSONObject中取出数据,很容易想到的就是从Map取出了:

复制代码
public String getString(String name) throws JSONException {
    Object object = get(name);  // get()方法就是执行Object result = nameValuePairs.get(name);
    String result = JSON.toString(object);
    if (result == null) {
        throw JSON.typeMismatch(name, object, "String");
    }
    return result;
}
复制代码

 

JsonObject的解析过程

一、 JsonObject还有一个带参数的构造函数:常用的是传递一个String类型的参数

public JSONObject(String json) throws JSONException {
    this(new JSONTokener(json));
}

 

二、 跟进去,发现主要执行的是JSONTokenernextValue()方法,在这个方法中主要是对数据进行解析;

复制代码
public Object nextValue() throws JSONException {
    int c = nextCleanInternal();
    switch (c) {
        case -1:
            throw syntaxError("End of input");

        case '{':
            return readObject();

        case '[':
            return readArray();

        case '\'':
        case '"':
            return nextString((char) c);

        default:
            pos--;
            return readLiteral();
    }
}
复制代码
  • nextCleanInternal方法中,它会从头到尾的逐个字符的解析,对于一些字符做一些处理。例如空格,换行,转义符等!
  • 当解析到[表示开始一个对象的读取,当解析到{表示一个数组的读取

 

三、 在readObject方法中,仍然是调用nextCleanInternal()方法,逐个得到解析的字符,下到解析到}.下面贴出重要代码

复制代码
int first = nextCleanInternal();  // 得到解析的字符
if (first == '}') {
    return result;
} else if (first != -1) {
    pos--;
}
.......
while (true) {
    Object name = nextValue();  // 解析得到键
    
    int separator = nextCleanInternal();
    if (separator != ':' && separator != '=') {
        throw syntaxError("Expected ':' after " + name);
    }
    if (pos < in.length() && in.charAt(pos) == '>') {
        pos++;
    }

    result.put((String) name, nextValue());  // 将解析得到的键值对,存放在map当中

    switch (nextCleanInternal()) {
        case '}':
            return result;
        case ';':
        case ',':
            continue;
        default:
            throw syntaxError("Unterminated object");
    }
}
复制代码

 

四、 nextValue方法比较关键,它流转解析的大部分工作!在nextValue中有一个readLiteral方法,针对一些类型做处理,得到解析之后的结果:

复制代码
private Object readLiteral() throws JSONException {
    String literal = nextToInternal("{}[]/\\:,=;# \t\f");

    if (literal.length() == 0) {
        throw syntaxError("Expected literal value");
    } else if ("null".equalsIgnoreCase(literal)) {
        return JSONObject.NULL;
    } else if ("true".equalsIgnoreCase(literal)) {
        return Boolean.TRUE;
    } else if ("false".equalsIgnoreCase(literal)) {
        return Boolean.FALSE;
    }

    /* try to parse as an integral type... */
    if (literal.indexOf('.') == -1) {
        int base = 10;
        String number = literal;
        if (number.startsWith("0x") || number.startsWith("0X")) {
            number = number.substring(2);
            base = 16;
        } else if (number.startsWith("0") && number.length() > 1) {
            number = number.substring(1);
            base = 8;
        }
        try {
            long longValue = Long.parseLong(number, base);
            if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
                return (int) longValue;
            } else {
                return longValue;
            }
        } catch (NumberFormatException e) {
            /*
             * This only happens for integral numbers greater than
             * Long.MAX_VALUE, numbers in exponential form (5e-10) and
             * unquoted strings. Fall through to try floating point.
             */
        }
    }

    /* ...next try to parse as a floating point... */
    try {
        return Double.valueOf(literal);
    } catch (NumberFormatException ignored) {
    }

    /* ... finally give up. We have an unquoted string */
    return new String(literal); // a new string avoids leaking memory
}
复制代码

 

五、至于JSONArray的解析与JsonObject的解析过程是一样的,它里面维护的是一个List

复制代码
private final List<Object> values;
public
JSONArray(JSONTokener readFrom) throws JSONException { Object object = readFrom.nextValue(); if (object instanceof JSONArray) { values = ((JSONArray) object).values; } else { throw JSON.typeMismatch(object, "JSONArray"); } }
复制代码

 

Gson的使用

一、我们在测试当中先加入一个Person类,方便测试:

复制代码
package com.tomhu.test;
public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
复制代码

 

二、 gson把对象转换成JSON格式

复制代码
Gson gson = new Gson();
Person person = new Person();
person.setName("linux");
person.setAge(23);
String str = gson.toJson(person);
System.out.println(str);
复制代码
  • 打印结果:  {"name":"linux","age":23}

 

三、 gsonjson格式解析成对象

String jsonData = "{'name':'刘力','age':19}";
Person person = gson.fromJson(jsonData, Person.class);
System.out.println(person.getName() + ", " + person.getAge());
  • 打印结果: 刘力, 19

 

四、 gsonList对象解析成Json格式:

复制代码
Gson gson = new Gson();
List<Person> persons = new ArrayList<Person>();
for (int i = 0; i < 2; i++) {
     Person p = new Person();
     p.setName("name" + i);
     p.setAge(i * 5);
     persons.add(p);
}
String str = gson.toJson(persons);
System.out.println(str);
复制代码
  • 打印结果: [{"name":"name0","age":0},{"name":"name1","age":5}]

 

五、 gsonJson格式解析成List对象:

复制代码
Gson gson = new Gson();
String str = "[{'name':'linux','age':10},{'name':'huhx','age':22}]";
List<Person> ps = gson.fromJson(str, new TypeToken<List<Person>>(){}.getType());
for (int i = 0; i < ps.size(); i++) {
    Person person = ps.get(i);
    System.out.print("name: " + person.getName() + " age: " + person.getAge());
}
复制代码
  • 打印结果:name: linux age: 10 name: huhx age: 22

 

JSON的使用实例

现在我们开始一个andriod客户端到web服务器的请求响应过程的实用案例,这里为了方便,我们把重要的代码全部贴出来:

流程: android发送post请求到服务器,服务器返回Json数据给客户端。android解析json数据并使用。

在android客户端:

一、 在AndroidManifest.xml中加入网络权限的声明:

<uses-permission android:name="android.permission.INTERNET"/>

 

二、 在MainActivity中加入一个事件,去发送请求:

// 发送请求
public void jsonTest(View view) {
    sendRequestWithHttpURLConnection();
}

 

三、 sendRequestWithHttpURLConnection是具体的发送请求的方法:

  •  首先我们是开启线程去发起请求的,请求地址是一个Servlet用作对数据的处理: 192.168.248.103是服务器的地址, http://192.168.248.103:8080/ListenerTest1/JsonServlet
  •  设置一些connection的参数,发送get请求,并且携带数据username=huhx,接收到数据用handler的方法处理信息!
复制代码
private void sendRequestWithHttpURLConnection() {
    // 开启线程来发起网络请求
    new Thread(new Runnable() {
        @Override
        public void run() {
            HttpURLConnection connection = null;
            try {
                URL url = new URL("http://192.168.248.103:8080/ListenerTest1/JsonServlet?username=huhx");
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(8000);
                connection.setReadTimeout(8000);
                connection.setRequestMethod("GET");

                // 如果服务器成功响应
                if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream in = connection.getInputStream();
                    // 下面对获取到的输入流进行读取
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }

                    Message message = new Message();
                    message.what = SHOW_RESPONSE;
                    message.obj = response.toString();
                    handler.sendMessage(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }
    }).start();
}
复制代码

 

四、 定义一个Handler,用于消息的接收处理:

复制代码
public static final int SHOW_RESPONSE = 0; // MainActivity中的全局变量
private final static String TAG = "Main2Activity";  // MainActivity中的全局变量

private Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SHOW_RESPONSE:
                String response = (String) msg.obj;
                jsonParseStr(response);
        }
    }
};
复制代码

 

五、 用JsonObjectjson的数据解析处理:

复制代码
// 得到返回数据,解析json数据
private void jsonParseStr(String response) {
    try {
        JSONObject jsonObject = new JSONObject(response);
        String name = (String) jsonObject.get("name");
        int age = (int) jsonObject.get("age");
        Log.i(TAG, "name: " + name + ", age: " + age);
    } catch (JSONException e) {
        e.printStackTrace();
    }
}
复制代码
  • 打印结果:  name: huhx, age: 22

 

在web服务器端:

一、 JsonServletdoGet方法,处理android客户端的请求:

复制代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String str = request.getParameter("username");
    System.out.println(str);
    Person person = new Person();
    person.setAge(22);
    person.setName("huhx");
    
    Gson gson = new Gson();
    String jsonStr = gson.toJson(person);
    response.getWriter().write(jsonStr);
}
复制代码
  • 打印结果: huhx

 

友情链接

 

点赞(0)

评论列表 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部