Android系列---JSON數(shù)據(jù)解析的實(shí)例
上篇隨筆詳細(xì)介紹了三種解析服務(wù)器端傳過(guò)來(lái)的xml數(shù)據(jù)格式,而對(duì)于服務(wù)器端來(lái)說(shuō),返回給客戶端的數(shù)據(jù)格式一般分為html、xml和json這三種格式,那么本篇隨筆將講解一下json這個(gè)知識(shí)點(diǎn),包括如何通過(guò)json-lib和gson這兩個(gè)json解析庫(kù)來(lái)對(duì)解析我們的json數(shù)據(jù),以及如何在我們的Android客戶端解析來(lái)自服務(wù)器端的json數(shù)據(jù),并更新到UI當(dāng)中。
一、什么是json
json(Javascript Object Notation)是一種輕量級(jí)的數(shù)據(jù)交換格式,相比于xml這種數(shù)據(jù)交換格式來(lái)說(shuō),因?yàn)榻馕鰔ml比較的復(fù)雜,而且需要編寫大段的代碼,所以客戶端和服務(wù)器的數(shù)據(jù)交換格式往往通過(guò)json來(lái)進(jìn)行交換。尤其是對(duì)于web開發(fā)來(lái)說(shuō),json數(shù)據(jù)格式在客戶端直接可以通過(guò)javascript來(lái)進(jìn)行解析。
json一共有兩種數(shù)據(jù)結(jié)構(gòu),一種是以 (key/value)對(duì)形式存在的無(wú)序的jsonObject對(duì)象,一個(gè)對(duì)象以“{”(左花括號(hào))開始,“}”(右花括號(hào))結(jié)束。每個(gè)“名稱”后跟一個(gè)“:”(冒號(hào));“‘名稱/值' 對(duì)”之間使用“,”(逗號(hào))分隔。
例如:{"name": "xiaoluo"}, 這就是一個(gè)最簡(jiǎn)單的json對(duì)象,對(duì)于這種數(shù)據(jù)格式,key值必須要是string類型,而對(duì)于value,則可以是string、number、object、array等數(shù)據(jù)類型:
另一種數(shù)據(jù)格式就是有序的value的集合,這種形式被稱為是jsonArray,數(shù)組是值(value)的有序集合。一個(gè)數(shù)組以“[”(左中括號(hào))開始,“]”(右中括號(hào))結(jié)束。值之間使用“,”(逗號(hào))分隔。
更多的有關(guān)json數(shù)據(jù)格式可以參加json的官網(wǎng),http://www.json.org/json-zh.html
二、解析json數(shù)據(jù)格式
這里將使用兩種json的解析庫(kù)來(lái)對(duì)我們的json數(shù)據(jù)格式進(jìn)行解析以及生成我們的json數(shù)據(jù)格式。
1.json-lib(http://json-lib.sourceforge.net/)
使用json-lib來(lái)進(jìn)行解析,我們需要引入第三方的包,因?yàn)閖son-lib分為了兩個(gè)版本,一個(gè)版本是針對(duì)于jdk1.3的,一個(gè)版本是針對(duì)于jdk1.5的,這里我們下載jdk1.5的這個(gè)json-lib包,其中還需要引入其他的幾個(gè)jar包:
下載好這幾個(gè)jar包后,加入到classpath中即可。我們來(lái)看看json-lib給我們提供的API。
我們最常用的兩個(gè)類就是 JSONObject和JSONArray這兩個(gè)類,分別代表了json對(duì)象和json數(shù)組,這兩個(gè)類都實(shí)現(xiàn)了 JSON 這個(gè)接口,下面我們通過(guò)幾個(gè)小例子來(lái)看看如何將我們常見的幾種數(shù)據(jù)格式轉(zhuǎn)換成我們的json對(duì)象(我們一般稱之為JSON數(shù)據(jù)的序列化)以及再將json對(duì)象在轉(zhuǎn)換成我們的數(shù)據(jù)格式(稱之為反序列化)。
①簡(jiǎn)單的javabean的序列化和反序列化
public class Person { private int id; private String name; private String address; public Person() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Person(int id, String name, String address) { super(); this.id = id; this.name = name; this.address = address; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", address=" + address + "]"; } }
首先我們定義一個(gè)簡(jiǎn)單的javabean對(duì)象,然后將一個(gè)Person對(duì)象轉(zhuǎn)換成json對(duì)象,然后再將這個(gè)json對(duì)象反序列化成我們的Person對(duì)象。
我們先定義一個(gè)JsonTools類,這個(gè)類有兩個(gè)靜態(tài)方法,我們可以通過(guò)這兩個(gè)方法來(lái)得到一個(gè)JSON類型的字符串對(duì)象,以及一個(gè)JSON對(duì)象
public class JsonTools { /** * 得到一個(gè)json類型的字符串對(duì)象 * @param key * @param value * @return */ public static String getJsonString(String key, Object value) { JSONObject jsonObject = new JSONObject(); //put和element都是往JSONObject對(duì)象中放入 key/value 對(duì) // jsonObject.put(key, value); jsonObject.element(key, value); return jsonObject.toString(); } /** * 得到一個(gè)json對(duì)象 * @param key * @param value * @return */ public static JSONObject getJsonObject(String key, Object value) { JSONObject jsonObject = new JSONObject(); jsonObject.put(key, value); return jsonObject; } }
我們可以直接通過(guò) JSONObject jsonObject = new JSONObject(); 這個(gè)方法就可以得到一個(gè)json對(duì)象,然后通過(guò)element()或者是put()方法來(lái)給我們的json對(duì)象添加key/value對(duì)。我們先來(lái)看看第一個(gè)例子,實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Person對(duì)象和json對(duì)象的轉(zhuǎn)換
Person person = new Person(1, "xiaoluo", "廣州"); // 將Person對(duì)象轉(zhuǎn)換成一個(gè)json類型的字符串對(duì)象 String personString = JsonTools.getJsonString("person", person); System.out.println(personString.toString());
我們看看控制臺(tái)的輸出:
{"person":{"address":"廣州","id":1,"name":"xiaoluo"}}
整個(gè)外面的大括號(hào)是一個(gè)json對(duì)象,里面有一對(duì)key/value,其中里面的{"address":"廣州","id":1,"name":"xiaoluo"}就是我們轉(zhuǎn)換成的json字符串對(duì)象
再來(lái)看看如何將json對(duì)象轉(zhuǎn)換成我們的bean對(duì)象
JSONObject jsonObject = JsonTools.getJsonObject("person", person); // 通過(guò)JSONObject的toBean方法可以將json對(duì)象轉(zhuǎn)換成一個(gè)javabean JSONObject personObject = jsonObject.getJSONObject("person"); Person person2 = (Person) JSONObject.toBean(personObject, Person.class); System.out.println(person2);
Person [id=1, name=xiaoluo, address=廣州]
②轉(zhuǎn)換List<Person>類型的對(duì)象
@Test public void testPersonsJson() { List<Person> persons = new ArrayList<Person>(); Person person = new Person(1, "xiaoluo", "廣州"); Person person2 = new Person(2, "android", "上海"); persons.add(person); persons.add(person2); String personsString = JsonTools.getJsonString("persons", persons); System.out.println(personsString); JSONObject jsonObject = JsonTools.getJsonObject("persons", persons); // List<Person>相當(dāng)于一個(gè)JSONArray對(duì)象 JSONArray personsArray = (JSONArray)jsonObject.getJSONArray("persons"); List<Person> persons2 = (List<Person>) personsArray.toCollection(personsArray, Person.class); System.out.println(persons2); }
{"persons":[{"address":"廣州","id":1,"name":"xiaoluo"},{"address":"上海","id":2,"name":"android"}]} [Person [id=1, name=xiaoluo, address=廣州], Person [id=2, name=android, address=上海]]
③List<Map<String, String>>類型的json對(duì)象轉(zhuǎn)換
@Test public void testMapJson() { List<Map<String, String>> list = new ArrayList<Map<String, String>>(); Map<String, String> map1 = new HashMap<String, String>(); map1.put("id", "001"); map1.put("name", "xiaoluo"); map1.put("age", "20"); Map<String, String> map2 = new HashMap<String, String>(); map2.put("id", "002"); map2.put("name", "android"); map2.put("age", "33"); list.add(map1); list.add(map2); String listString = JsonTools.getJsonString("list", list); System.out.println(listString); JSONObject jsonObject = JsonTools.getJsonObject("list", list); JSONArray listArray = jsonObject.getJSONArray("list"); List<Map<String, String>> list2 = (List<Map<String, String>>) listArray.toCollection(listArray, Map.class); System.out.println(list2); }
{"list":[{"id":"001","age":"20","name":"xiaoluo"},{"id":"002","age":"33","name":"android"}]} [{id=001, name=xiaoluo, age=20}, {id=002, name=android, age=33}]
通過(guò)上面的例子,我們可以了解了如何通過(guò)json-lib這個(gè)解析庫(kù)來(lái)實(shí)現(xiàn)javabean、List、Map等數(shù)據(jù)和json數(shù)據(jù)的互相轉(zhuǎn)換
2.gson(http://code.google.com/p/google-gson/)
下面我們來(lái)看看Google提供的gson這個(gè)json解析庫(kù),同樣我們需要去下載gson這個(gè)jar包,導(dǎo)入到我們的項(xiàng)目中
使用gson,我們可以非常輕松的實(shí)現(xiàn)數(shù)據(jù)對(duì)象和json對(duì)象的相互轉(zhuǎn)化,其中我們最常用的就是兩個(gè)方法,一個(gè)是fromJSON(),將json對(duì)象轉(zhuǎn)換成我們需要的數(shù)據(jù)對(duì)象,另一個(gè)是toJSON(),這個(gè)就是將我們的數(shù)據(jù)對(duì)象轉(zhuǎn)換成json對(duì)象。下面我們也通過(guò)一個(gè)綜合的例子來(lái)看看gson的使用方法:
public class JsonService { public Person getPerson() { Person person = new Person(1, "xiaoluo", "廣州"); return person; } public List<Person> getPersons() { List<Person> persons = new ArrayList<Person>(); Person person = new Person(1, "xiaoluo", "廣州"); Person person2 = new Person(2, "android", "上海"); persons.add(person); persons.add(person2); return persons; } public List<String> getString() { List<String> list = new ArrayList<String>(); list.add("廣州"); list.add("上海"); list.add("北京"); return list; } public List<Map<String, String>> getMapList() { List<Map<String, String>> list = new ArrayList<Map<String, String>>(); Map<String, String> map1 = new HashMap<String, String>(); map1.put("id", "001"); map1.put("name", "xiaoluo"); map1.put("age", "20"); Map<String, String> map2 = new HashMap<String, String>(); map2.put("id", "002"); map2.put("name", "android"); map2.put("age", "33"); list.add(map1); list.add(map2); return list; } }
public static void main(String[] args) { Gson gson = new Gson(); JsonService jsonService = new JsonService(); Person person = jsonService.getPerson(); System.out.println("person: " + gson.toJson(person)); // 對(duì)于Object類型,使用 fromJson(String, Class)方法來(lái)將Json對(duì)象轉(zhuǎn)換成Java對(duì)象 Person person2 = gson.fromJson(gson.toJson(person), Person.class); System.out.println(person2); System.out.println("------------------------------------------------"); List<Person> persons = jsonService.getPersons(); System.out.println("persons: " + gson.toJson(persons)); /* * 對(duì)于泛型對(duì)象,使用fromJson(String, Type)方法來(lái)將Json對(duì)象轉(zhuǎn)換成對(duì)應(yīng)的泛型對(duì)象 * new TypeToken<>(){}.getType()方法 */ List<Person> persons2 = gson.fromJson(gson.toJson(persons), new TypeToken<List<Person>>(){}.getType()); System.out.println(persons2); System.out.println("------------------------------------------------"); List<String> list = jsonService.getString(); System.out.println("String---->" + gson.toJson(list)); List<String> list2 = gson.fromJson(gson.toJson(list), new TypeToken<List<String>>(){}.getType()); System.out.println("list2---->" + list2); System.out.println("------------------------------------------------"); List<Map<String, String>> listMap = jsonService.getMapList(); System.out.println("Map---->" + gson.toJson(listMap)); List<Map<String, String>> listMap2 = gson.fromJson(gson.toJson(listMap), new TypeToken<List<Map<String, String>>>(){}.getType()); System.out.println("listMap2---->" + listMap2); System.out.println("------------------------------------------------"); }
看看控制臺(tái)的輸出:
person: {"id":1,"name":"xiaoluo","address":"廣州"}
Person [id=1, name=xiaoluo, address=廣州]
------------------------------------------------
persons: [{"id":1,"name":"xiaoluo","address":"廣州"},{"id":2,"name":"android","address":"上海"}]
[Person [id=1, name=xiaoluo, address=廣州], Person [id=2, name=android, address=上海]]
------------------------------------------------
String---->["廣州","上海","北京"]
list2---->[廣州, 上海, 北京]
------------------------------------------------
Map---->[{"id":"001","age":"20","name":"xiaoluo"},{"id":"002","age":"33","name":"android"}]
listMap2---->[{id=001, age=20, name=xiaoluo}, {id=002, age=33, name=android}]
------------------------------------------------
三、在Android客戶端解析服務(wù)器端的json數(shù)據(jù)
下面我們來(lái)完成一個(gè)綜合的例子,Android客戶端通過(guò)一個(gè)AsyncTask異步任務(wù)請(qǐng)求服務(wù)器端的某些數(shù)據(jù),然后在解析完這些數(shù)據(jù)后,將得到的數(shù)據(jù)內(nèi)容更新到我們的Spinner這個(gè)UI控件當(dāng)中。
我們首先來(lái)看下服務(wù)器端的代碼:
@WebServlet("/CityServlet") public class CityServlet extends HttpServlet { private static final long serialVersionUID = 1L; public CityServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); PrintWriter writer = response.getWriter(); String type = request.getParameter("type"); if("json".equals(type)) { List<String> cities = new ArrayList<String>(); cities.add("廣州"); cities.add("上海"); cities.add("北京"); cities.add("湖南"); Map<String, List<String>> map = new HashMap<String, List<String>>(); map.put("cities", cities); String citiesString = JSON.toJSONString(map); writer.println(citiesString); } writer.flush(); writer.close(); } }
如果客戶端請(qǐng)求的參數(shù)是type=json,則響應(yīng)給客戶端一個(gè)json數(shù)據(jù)格式
接著來(lái)看看客戶端的代碼,首先看看客戶端的布局文件,其實(shí)就是一個(gè)按鈕和一個(gè)Spinner控件,當(dāng)點(diǎn)擊按鈕后,通過(guò)http協(xié)議請(qǐng)求服務(wù)器端的數(shù)據(jù),然后在接收到后再更新我們的Spinner控件的數(shù)據(jù)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginLeft="64dp" android:layout_marginTop="64dp" android:textSize="20sp" android:text="城市" /> <Spinner android:id="@+id/spinner" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/textView1" android:layout_toRightOf="@id/textView1"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/textView1" android:layout_below="@+id/spinner" android:layout_marginLeft="22dp" android:layout_marginTop="130dp" android:text="加載數(shù)據(jù)" /> </RelativeLayout>
在Android客戶端寫一個(gè)解析json數(shù)據(jù)格式的類:
public class JsonUtils { /** * @param citiesString 從服務(wù)器端得到的JSON字符串?dāng)?shù)據(jù) * @return 解析JSON字符串?dāng)?shù)據(jù),放入List當(dāng)中 */ public static List<String> parseCities(String citiesString) { List<String> cities = new ArrayList<String>(); try { JSONObject jsonObject = new JSONObject(citiesString); JSONArray jsonArray = jsonObject.getJSONArray("cities"); for(int i = 0; i < jsonArray.length(); i++) { cities.add(jsonArray.getString(i)); } } catch (Exception e) { e.printStackTrace(); } return cities; } }
當(dāng)然我們的HttpUtils類也不可少:
public class HttpUtils { /** * @param path 請(qǐng)求的服務(wù)器URL地址 * @param encode 編碼格式 * @return 將服務(wù)器端返回的數(shù)據(jù)轉(zhuǎn)換成String */ public static String sendPostMessage(String path, String encode) { String result = ""; HttpClient httpClient = new DefaultHttpClient(); try { HttpPost httpPost = new HttpPost(path); HttpResponse httpResponse = httpClient.execute(httpPost); if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity httpEntity = httpResponse.getEntity(); if(httpEntity != null) { result = EntityUtils.toString(httpEntity, encode); } } } catch (Exception e) { e.printStackTrace(); } finally { httpClient.getConnectionManager().shutdown(); } return result; }
最后來(lái)看看我們的MainActivity類:
public class MainActivity extends Activity { private Spinner spinner; private Button button; private ArrayAdapter<String> adapter; private ProgressDialog dialog; private final String CITY_PATH_JSON = "http://172.25.152.34:8080/httptest/CityServlet?type=json"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); spinner = (Spinner)findViewById(R.id.spinner); button = (Button)findViewById(R.id.button); dialog = new ProgressDialog(MainActivity.this); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dialog.setTitle("提示信息"); dialog.setMessage("loading......"); dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); dialog.setCancelable(false); new MyAsyncTask().execute(CITY_PATH_JSON); } }); } public class MyAsyncTask extends AsyncTask<String, Void, List<String>> { @Override protected void onPreExecute() { dialog.show(); } @Override protected List<String> doInBackground(String... params) { List<String> cities = new ArrayList<String>(); String citiesString = HttpUtils.sendPostMessage(params[0], "utf-8"); // 解析服務(wù)器端的json數(shù)據(jù) cities = JsonUtils.parseCities(citiesString);return cities; } @Override protected void onPostExecute(List<String> result) { adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_spinner_item, result); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); dialog.dismiss(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } }
當(dāng)然別往了開啟我們的網(wǎng)絡(luò)授權(quán)
<uses-permission android:name="android.permission.INTERNET"/>
最后我們來(lái)看看效果圖:
這樣我們就完成了客戶端與服務(wù)器端通過(guò)json來(lái)進(jìn)行數(shù)據(jù)的交換
總結(jié):本篇隨筆主要講解了JSON這種輕量級(jí)的數(shù)據(jù)交換格式的概念,以及講解了兩種解析json數(shù)據(jù)的解析類(json-lib以及gson),最后通過(guò)一個(gè)小例子實(shí)現(xiàn)了在Android客戶端和服務(wù)器端使用json這種數(shù)據(jù)格式來(lái)進(jìn)行數(shù)據(jù)的交換。
原文鏈接:http://www.cnblogs.com/xiaoluo501395377/p/3446605.html
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android編程實(shí)現(xiàn)自定義Dialog的大小自動(dòng)控制方法示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義Dialog的大小自動(dòng)控制方法,結(jié)合實(shí)例形式分析了Android自定義Dialog對(duì)話框的屬性操作技巧與大小動(dòng)態(tài)控制實(shí)現(xiàn)方法,需要的朋友可以參考下2017-09-09DialogFragment運(yùn)行原理及使用方法詳解
這篇文章主要介紹了DialogFragment運(yùn)行原理及使用方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10???????Android?H5通用容器架構(gòu)設(shè)計(jì)詳解
這篇文章主要介紹了???????Android?H5通用容器架構(gòu)設(shè)計(jì)詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09Android小程序?qū)崿F(xiàn)個(gè)人信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Android小程序?qū)崿F(xiàn)個(gè)人信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05Android UI設(shè)計(jì)系列之ImageView實(shí)現(xiàn)ProgressBar旋轉(zhuǎn)效果(1)
這篇文章主要為大家詳細(xì)介紹了Android UI設(shè)計(jì)之ImageView實(shí)現(xiàn)ProgressBar旋轉(zhuǎn)效果,具有一定的實(shí)用性和參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06Android Studio輕松構(gòu)建自定義模板的步驟記錄
這篇文章主要給大家介紹了關(guān)于Android Studio輕松構(gòu)建自定義模板的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10Android編程實(shí)現(xiàn)對(duì)電池狀態(tài)的監(jiān)視功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)對(duì)電池狀態(tài)的監(jiān)視功能,涉及Android基于廣播實(shí)現(xiàn)針對(duì)電源電量的判定與監(jiān)視技巧,需要的朋友可以參考下2016-11-11詳解Android中提示對(duì)話框(ProgressDialog和DatePickerDialog和TimePickerDi
這篇文章主要介紹了詳解Android中提示對(duì)話框(ProgressDialog和DatePickerDialog和TimePickerDialog&PopupWindow)的相關(guān)資料,需要的朋友可以參考下2016-01-01