【聲明】
歡迎轉載,但請保留文章原始出處→_→
生命壹號:http://www.cnblogs.com/smyhvae/
文章來源:http://www.cnblogs.com/smyhvae/p/4063452.html
【正文】
文章回顧: Android網絡之數據解析----SAX方式解析XML數據
一、Json數據的介紹
Json(JavaScript Object Notation) 是一種輕量級的數據交換格式。它基於JS的一個子集。 Json采用完全獨立於語言的文本格式,這使得Json成為理想的數據交換語言。易於人閱讀和編寫,同時也易於機器解析和生成。
Json簡單來說就是JS中的對象和數組,所以Json也存在兩種結構:對象、數組。
1、Json對象:
含義:是“‘鍵/值’對”的無序集合
格式:Json對象定義在花括號“{}”內,以Key:value鍵值對的形式存放數據,多個鍵值對之間使用逗號“,”隔開,多個數據使用分號“;”隔開。
舉例:
{ “name”:”jackson”, “age”:100 }
注:不同的語言中,它被理解為對象(object)、紀錄(record)、結構(struct)、字典(dictionary)、哈希表(hash table)、有鍵列表(keyed list)、或者關聯數組 (associative array)。
2、Json數組:
含義:數組是值(value)的有序集合
格式:Json數組定義在方括號“[]”內,以字符串的形式存放數據,值之間使用逗號“,”隔開,多個數據使用分號“;”隔開。
舉例:
1 { 2 “students”: 3 [ 4 {“name”:”jackson”,“age”:100}, 5 {“name”:”michael”,”age”:51} 6 ] 7 }
一般情況下,我們用jsp+servlet作服務器端,生成Json的數據;然后在客戶端解析Json的數據。
解析JSON數據, 首先需要明確待解析的是JSON Object還是JSON array, 然后需要確定采用哪種解析技術。android平台上一般有以下幾種解析技術可供選擇:android內置的org.json包(Json),google的開源庫GSON,還有一些第三方的開源庫如Jackson、FastJson等。我們今天來學習一下使用開源庫GSON來解析Json數據。
二、Gson解析Json的基本思路
首先在服務器端,將服務器端的Person對象通過Gson解析成json的字符串;然后在客戶端,通過Gson類將json的字符串還原為Person對象。Gson支持任意復雜Java對象包括沒有源代碼的對象。
如果我們將Person對象看成一個泛型,那么不管服務器端的Person對象是什么類型,都可以解析出來。
Gson庫神奇在哪里呢?如果解析的是Json對象,它主要就是可以將一段Json格式的字符串自動映射成一個對象,從而不需要我們再手動去編寫代碼進行解析了。比如一段Json格式的數據如下:
{"name":"tom","age":20}
那我們就可以寫一個Person類,並加入name和age這兩個字段,只需要簡單地調用如下代碼就可以將Json數據自動解析成一個Person對象了:
Gson gson = new Gson(); Person person = gson.fromJson(jsonData,Person.class);
如果解析的是Json對象數組,就要麻煩一點,需要借助Typetoken(官方提供的一種反射機制)將期望解析成的數據類型傳入到fromJson()方法中,如下所示:
List<Person> people = gson.fromJson(jsonData, new TypeToken<List<Person>>().getType());
基本用法就是這樣,我們現在來看一下具體的實現步驟吧。
三、Gson解析Json的步驟(代碼實現)
現在通過一個示例程序來講解一下SAX是怎么解析XML文件的,這個示例程序是運行在Android平台上的,為了模擬真實情況,在tomcat服務器上放置了一個兩個靜態的XML文件:person.json和perons.json,前者代表對象,后者代表對象數組。即在D:\apache-tomcat-8.0.14\webapps\ROOT目錄中新建文件person.json和perons.json.
person.json的內容如下:
{ "id": 1, "name": "smyhvae", "address":"成都" }
需要特別注意的是,要注意json文件的格式。例如第4行的后面不要有逗號(我就是因為這個低級錯誤,導致后來調試程序,調了半個多小時才發覺)
persons.json的內容如下:
[{ "id": 1, "name": "smyhvae", "address":"成都" }, { "id": 2, "name": "許嵩", "address":"合肥" }]
注:關於tomcat服務器的配置,如果不清楚的話,請參照本人另外一篇博客的第三段:JavaWeb學習(一)----JSP簡介及入門(含Tomcat的使用)
因為我電腦的IP地址是192.168.1.112。現在我們在瀏覽器輸入http://192.168.1.112:8080/person.json和http://192.168.1.112:8080/persons.json,顯示效果如下:
上方的中文出現了亂碼,不過沒關系,在稍后解析的時候是不會出現這種情況的。
現在我們需要做的是:通過Android程序去獲取並解析這段Json數據。因為是Android程序,所以別忘了賦予其訪問網絡的權限。
整個工程文件的目錄結構如下:
(1)下載並添加Gson的jar包:
下載地址:https://code.google.com/p/google-gson/ 網頁界面如下:
點擊上圖中的紅框部分,出現如下界面:
上圖中的紅框部分gson-2.3.jar就是我們需要下載的內容,如果需要幫助文檔的話,也可以把箭頭處的文件下載下來。然后把gson-2.3.jar拷貝到工程文件的libs目錄下,Gson庫就自動添加到項目中去了。
(2)【新建工具類HttpUtils】通過URLHttpConnection獲取服務器上的XML流:返回的是字符串
1 package com.example.android_gson_json.http; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.net.HttpURLConnection; 7 import java.net.URL; 8 9 10 //通過HttpURLCnnection獲取鏈接里的數據,放到流里,然后把流里面的數據轉換為字符串(借鑒於:老羅老版本1-04) 11 public class HttpUtils { 12 13 public HttpUtils() { 14 // TODO Auto-generated constructor stub 15 } 16 17 public static String getJsonContent(String url_path) { 18 try { 19 URL url = new URL(url_path); 20 HttpURLConnection connection = (HttpURLConnection) url 21 .openConnection(); 22 connection.setConnectTimeout(3000); 23 connection.setRequestMethod("GET"); 24 connection.setDoInput(true); 25 int code = connection.getResponseCode(); 26 if (code == 200) { 27 return changeInputStream(connection.getInputStream()); 28 } 29 } catch (Exception e) { 30 // TODO: handle exception 31 } 32 return ""; 33 } 34 35 private static String changeInputStream(InputStream inputStream) { 36 // TODO Auto-generated method stub 37 String jsonString = ""; 38 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 39 int len = 0; 40 byte[] data = new byte[1024]; 41 try { 42 while ((len = inputStream.read(data)) != -1) { 43 outputStream.write(data, 0, len); 44 } 45 jsonString = new String(outputStream.toByteArray()); 46 } catch (IOException e) { 47 // TODO Auto-generated catch block 48 e.printStackTrace(); 49 } 50 return jsonString; 51 } 52 }
(3)【新建類Person】新建實體類Person,用於存放解析完成后的對象數據
1 package com.example.android_gson_json.domain; 2 3 public class Person { 4 private int id; 5 private String name; 6 private String address; 7 public Person() { 8 super(); 9 } 10 public Person(int id, String name, String address) { 11 super(); 12 this.id = id; 13 this.name = name; 14 this.address = address; 15 } 16 public int getId() { 17 return id; 18 } 19 public void setId(int id) { 20 this.id = id; 21 } 22 public String getName() { 23 return name; 24 } 25 public void setName(String name) { 26 this.name = name; 27 } 28 public String getAddress() { 29 return address; 30 } 31 public void setAddress(String address) { 32 this.address = address; 33 } 34 @Override 35 public String toString() { 36 return "Person [id=" + id + ", name=" + name + ", address=" + address 37 + "]"; 38 } 39 40 }
(4)【新建類GsonTools】真正用於解析Json數據
1 package com.example.android_gson_json.gson; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import com.google.gson.Gson; 7 import com.google.gson.reflect.TypeToken; 8 9 public class GsonTools { 10 11 public GsonTools() { 12 // TODO Auto-generated constructor stub 13 } 14 15 //使用Gson進行解析Person 16 public static <T> T getPerson(String jsonString, Class<T> cls) { 17 T t = null; 18 try { 19 Gson gson = new Gson(); 20 t = gson.fromJson(jsonString, cls); 21 } catch (Exception e) { 22 // TODO: handle exception 23 } 24 return t; 25 } 26 27 28 // 使用Gson進行解析 List<Person> 29 public static <T> List<T> getPersons(String jsonString, Class<T> cls) { 30 List<T> list = new ArrayList<T>(); 31 try { 32 Gson gson = new Gson(); 33 list = gson.fromJson(jsonString, new TypeToken<List<T>>() { 34 }.getType()); 35 } catch (Exception e) { 36 } 37 return list; 38 } 39 40 }
上面有兩個方法,分別用於解析Person對象、List嵌套的Person。如果還有更復雜的數據類型,以后再說吧~O(∩_∩)O~這里只需要注意關鍵的思路就行。
核心代碼:19至20行、32至34行
(5)在MainActicity中實例化:即實例化需要訪問的鏈接path並解析它
布局界面很簡單,只有兩個按鈕控件,這里就不展示布局代碼了。點擊按鈕后,觸發點擊事件,因為是Android4.0+,所以不能在主線程中訪問網絡,需要另起一個線程,這里使用Thread類。代碼如下:
1 package com.example.android_gson_json; 2 3 import java.util.List; 4 5 import android.app.Activity; 6 import android.os.Bundle; 7 import android.util.Log; 8 import android.view.View; 9 import android.view.View.OnClickListener; 10 import android.widget.Button; 11 12 import com.example.android_gson_json.domain.Person; 13 import com.example.android_gson_json.gson.GsonTools; 14 import com.example.android_gson_json.http.HttpUtils; 15 16 public class MainActivity extends Activity implements OnClickListener { 17 18 private Button button1, button2; 19 private static final String TAG = "MainActivity"; 20 21 @Override 22 protected void onCreate(Bundle savedInstanceState) { 23 super.onCreate(savedInstanceState); 24 setContentView(R.layout.activity_main); 25 26 button1 = (Button) this.findViewById(R.id.button1); 27 button2 = (Button) this.findViewById(R.id.button2); 28 button1.setOnClickListener(this); 29 button2.setOnClickListener(this); 30 } 31 32 //點擊按鈕,開始使用Gson解析Json數據:Person對象、List嵌套的Person對象的集合 33 @Override 34 public void onClick(final View v) { 35 Thread thread = new Thread(new Runnable() { 36 37 @Override 38 public void run() { 39 switch (v.getId()) { 40 case R.id.button1: 41 String path = "http://192.168.1.112:8080/person.json"; 42 String jsonString = HttpUtils.getJsonContent(path);//從網絡獲取數據 43 Person person = GsonTools.getPerson(jsonString, Person.class);//解析json數據 44 Log.i(TAG, person.toString()); 45 break; 46 case R.id.button2: 47 String path2 = "http://192.168.1.112:8080/persons.json"; 48 String jsonString2 = HttpUtils.getJsonContent(path2);//從網絡獲取數據 49 List<Person> list = GsonTools.getPersons(jsonString2, Person.class);//解析json數據 50 Log.i(TAG, list.toString()); 51 break; 52 } 53 54 } 55 }); 56 thread.start(); 57 58 } 59 60 }
核心代碼:43行、49行
(6)添加網絡權限:(這個千萬不要忘記了)
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.INTERNET"/>
程序運行在模擬器上運行后,界面如下:
分別點擊這兩個按鈕,后台打印的日志如下:
在真機上運行的效果如下:
說明Json數據解析成功,大功告成。
最后聲明:
其實,如果是在模擬器上運行,即使不添加網絡權限,也是沒有關系的;但是,如果在真機上運行(前提是真機和電腦在同一個局域網),不添加網絡權限,程序是絕對運行不了的,點擊按鈕,程序就會死掉,這個地方又耽誤了我半個小時,罪過。
【工程文件】
鏈接:http://pan.baidu.com/s/1mgj0FY4
密碼:61u3