1.Json 和 Xml
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C++、C#、Java、JavaScript、Perl、Python等)。这些特性使JSON成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成(网络传输速率)。
[ XML ]
优点::
(1). 格式统一, 符合标准
(2). 容易与其他系统进行远程交互, 数据共享比较方便
缺点:
(1). XML文件格式文件庞大, 格式复杂, 传输占用带宽
(2). 服务器端和客户端都需要花费大量代码来解析XML, 不论服务器端和客户端代码变的异常复杂和不容易维护
(3). 客户端不同浏览器之间解析XML的方式不一致, 需要重复编写很多代码
(4). 服务器端和客户端解析XML花费资源和时间
[ JSON ]
优点:
(1). 数据格式比较简单, 易于读写, 格式都是压缩的, 占用带宽小
(2). 易于解析这种语言, 客户端JavaScript可以简单的通过eval()进行JSON数据的读取
(3). 支持多种语言, 包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等语言服务器端语言, 便于服务器端的解析
(4). 在PHP世界, 已经有PHP-JSON和JSON-PHP出现了, 便于PHP序列化后的程序直接调用. PHP服务器端的对象、数组等能够直接生JSON格式, 便于客户端的访问提取.
(5). 因为JSON格式能够直接为服务器端代码使用, 大大简化了服务器端和客户端的代码开发量, 但是完成的任务不变, 且易于维护
缺点:
(1). 没有XML格式这么推广的深入人心和使用广泛, 没有XML那么通用性
(2). JSON格式目前在Web Service中推广还属于初级阶段
2.JSON语法
JSON 语法是 JavaScript 对象表示语法的子集。
数据在键值对中
数据由逗号分隔
花括号保存对象
方括号保存数组
JSON 名称/值对
JSON 数据的书写格式是:名称/值对。
名称/值对组合中的名称写在前面(在双引号中),值对写在后面(同样在双引号中),中间用冒号隔开:
"firstName":"John"
这很容易理解,等价于这条 JavaScript 语句:
firstName="John"
一个对象以"{"开始,以"}"结束。 每个"名称"后跟一个":" ,"键/值"对"之间使用","分隔
但是,当将多个"名称 / 值对"串在一起时,JSON 就会体现出它的价值了。首先,可以创建包含多个"名称 / 值对"的 记录,比如:
{"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"}
1 var json = '{"name":"imooc"}'; //这个是正确的JSON格式
2
3 var json = "{\"name\":\"imooc\"}"; //这个也是正确的JSON格式
4
5 var json = '{name:"imooc"}'; //这个是错误的JSON格式,因为属性名没有用双引号包裹
6
7 var json = "{'name':'imooc'}";//这个也是错误的JSON格式,属性名用双引号包裹,而它用了单引号
8
9 //检验JSON格式是否正确,可以使用 JSON.parse(json); 如果是正确的JSON格式,会返回一个对象
10 //否则会报错
11
12 //如果是对象的话,属性名可以不用双引号包裹
13
14 var obj = {name:"imooc"};15 var obj = {"name":"imooc"};16 var obj = {'name':'imooc'};17 var obj = {"name":'imooc'};18 var obj = {'name':"imooc"};19
20 //上述写法都是正确的。一般使用第一种形式最多,有些人可能为了保证跟JSON格式的字符串保持一致性,
21 //也会使用第二种形式。。最后3种形式虽然是正确的,但不建议使用,容易挨打
JSON表示数组
当需要表示一组值时,JSON 不但能够提高可读性,而且可以减少复杂性。例如,假设您希望表示一个人名列表。在XML中,需要许多开始标记和结束标记;如果使用典型的名称 / 值对(就像在本系列前面文章中看到的那种名称 / 值对),那么必须建立一种专有的数据格式,或者将键名称修改为 person1-firstName这样的形式。
如果使用 JSON,就只需将多个带花括号的记录分组在一起:
{"people":[
{"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"},
{"firstName":"Jason","lastName":"Hunter","email":"bbbb"},
{"firstName":"Elliotte","lastName":"Harold","email":"cccc"}
]
}
这不难理解。在这个示例中,只有一个名为 people的变量,值是包含三个条目的数组,每个条目是一个人的记录,其中包含名、姓和电子邮件地址。上面的示例演示如何用括号将记录组合成一个值。当然,可以使用相同的语法表示多个值(每个值包含多个记录):
{"programmers": [{"firstName": "Brett","lastName": "McLaughlin","email": "aaaa"}, {"firstName": "Jason","lastName": "Hunter","email": "bbbb"}, {"firstName": "Elliotte","lastName": "Harold","email": "cccc"}],"authors": [{"firstName": "Isaac","lastName": "Asimov","genre": "sciencefiction"}, {"firstName": "Tad","lastName": "Williams","genre": "fantasy"}, {"firstName": "Frank","lastName": "Peretti","genre": "christianfiction"}],"musicians": [{"firstName": "Eric","lastName": "Clapton","instrument": "guitar"}, {"firstName": "Sergei","lastName": "Rachmaninoff","instrument": "piano"}]
}
jsonobject json对象。
{
mts:'1351234',
province:'重庆',
catName:'中国移动',
telString:'13512345678',
areaVid:'29404',
ispVid:'3236139',
carrier:'重庆移动'
}
3.下面结合一个案例,说明Android下如何通过网络访问解析Json数据:
(1)我们新建一个Android项目,如下:
(2)布局文件activity_main.xml:
1
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical"
6 tools:context="com.himi.json.MainActivity" >
7
8
10 android:layout_width="match_parent"
11 android:layout_height="wrap_content"
12 android:hint="请输入电话号码"
13 android:inputType="phone"/>
14
16 android:layout_height="wrap_content"
17 android:text="查询"
18 android:onClick="click"
19 />
20
21
布局效果图如下:
(3)我们获得网络端的Json数据是如下格式的:
我们要知道真正的JSON数据实体是:就是大括号包裹的部分就是JSON数据,这里就是没有"_GetZoneResult_= "(末尾含有一个空格)
{
mts:'1351234',
province:'重庆',
catName:'中国移动',
telString:'13512345678',
areaVid:'29404',
ispVid:'3236139',
carrier:'重庆移动'
}
回到MainActivity.java:
1 packagecom.himi.json;2
3 importjava.io.IOException;4 importjava.io.InputStream;5 importjava.net.HttpURLConnection;6 importjava.net.MalformedURLException;7 importjava.net.ProtocolException;8 importjava.net.URL;9
10 importorg.json.JSONObject;11
12 importandroid.app.Activity;13 importandroid.os.Bundle;14 importandroid.view.View;15 importandroid.widget.EditText;16 importandroid.widget.Toast;17
18 public class MainActivity extendsActivity {19 privateEditText et_phone;20
21 @Override22 protected voidonCreate(Bundle savedInstanceState) {23 super.onCreate(savedInstanceState);24 setContentView(R.layout.activity_main);25 et_phone =(EditText) findViewById(R.id.et_phone);26
27
28
29 }30
31 public voidclick(View view) {32 String phone =et_phone.getText().toString().trim();33 final String path = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel="+phone;34
35 newThread() {36 public voidrun() {37 try{38 URL url = newURL(path);39 HttpURLConnection conn =(HttpURLConnection) url.openConnection();40 conn.setRequestMethod("GET");41 conn.setConnectTimeout(5000);42 conn.setReadTimeout(5000);43 int code =conn.getResponseCode();44 if (code == 200) {45 //得打JOSN数据,字符串
46 InputStream is =conn.getInputStream();47 String json = StreamTools.readStream(is).replace("_GetZoneResult_= ", "");48 //System.out.println(json);
49 JSONObject jsonObject = newJSONObject();50 final String catName = jsonObject.getString("catName");51 final String province = jsonObject.getString("province");52 runOnUiThread(newRunnable() {53 public voidrun() {54 Toast.makeText(MainActivity.this, "运营商: "+catName+"\n归属地: "+province,55 0).show();56 };57 });58 } else{59 runOnUiThread(newRunnable() {60 public voidrun() {61 Toast.makeText(MainActivity.this, "资源没有找到或者是服务器出了问题",0).show();62 };63 });64
65 }66 } catch(Exception e) {67 //TODO 自动生成的 catch 块
68 e.printStackTrace();69 runOnUiThread(newRunnable() {70 public voidrun() {71 Toast.makeText(MainActivity.this, "访问网络失败",0).show();72 };73 });74
75 }76 };77 }.start();78 }79
80
81 }
Toast土司是更新UI操作,它是不能出现在子线程new Thread()之中的,之前说过这里可以使用handler消息机制通知主线程进行UI更新,这里有了更加方便的API就是runOnUiThread()方法,这个方法的源码如下:
1 public final voidrunOnUiThread(Runnable action) {2 if (Thread.currentThread() !=mUiThread) {3 mHandler.post(action);4 } else{5 action.run();6 }7 }
这个方法将Runnable接口内部执行的内容在主线程执行;
这里源码可以看出它是先判断当前线程是否是UI主线程,不是的话就利用handler发送消息给主线程进行相应操作,如果当前线程是主线程,就直接在当前线程中执行。
还有这里利用我们之前自己编写的一个API,将流转化为字符串的工具类StreamTools:
1 packagecom.himi.json;2
3 importjava.io.ByteArrayOutputStream;4 importjava.io.IOException;5 importjava.io.InputStream;6
7 /**
8 * 流的工具类9 *10 *@authorAdministrator11 *12 */
13 public classStreamTools {14 /**
15 * 把输入流的内容转换成字符串16 *17 *@paramis18 *@returnnull解析失败, string读取成功19 */
20 public staticString readStream(InputStream is) {21 try{22 ByteArrayOutputStream baos = newByteArrayOutputStream();23 byte[] buffer = new byte[1024];24 int len = -1;25 while ((len = is.read(buffer)) != -1) {26 baos.write(buffer, 0, len);27 }28 is.close();29 String temptext = newString(baos.toByteArray());30 return new String(baos.toByteArray(), "gbk");31 } catch(IOException e) {32 e.printStackTrace();33 return null;34 }35 }36 }
(4)其实上面出现了很多的runOnUiThread(),我们可以抽取一个方法包裹这部分代码:
代码优化如下:
1 packagecom.himi.json;2
3 importjava.io.IOException;4 importjava.io.InputStream;5 importjava.net.HttpURLConnection;6 importjava.net.MalformedURLException;7 importjava.net.ProtocolException;8 importjava.net.URL;9
10 importorg.json.JSONObject;11
12 importandroid.app.Activity;13 importandroid.os.Bundle;14 importandroid.view.View;15 importandroid.widget.EditText;16 importandroid.widget.Toast;17
18 public class MainActivity extendsActivity {19 privateEditText et_phone;20
21 @Override22 protected voidonCreate(Bundle savedInstanceState) {23 super.onCreate(savedInstanceState);24 setContentView(R.layout.activity_main);25 et_phone =(EditText) findViewById(R.id.et_phone);26
27
28
29 }30
31 public voidclick(View view) {32 String phone =et_phone.getText().toString().trim();33 final String path = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel="+phone;34
35 newThread() {36 public voidrun() {37 try{38 URL url = newURL(path);39 HttpURLConnection conn =(HttpURLConnection) url.openConnection();40 conn.setRequestMethod("GET");41 conn.setConnectTimeout(5000);42 conn.setReadTimeout(5000);43 int code =conn.getResponseCode();44 if (code == 200) {45 //得打JOSN数据,字符串
46 InputStream is =conn.getInputStream();47 String json = StreamTools.readStream(is).replace("__GetZoneResult_= ", "");48 //System.out.println(json);
49 JSONObject jsonObject = newJSONObject(json);50 final String catName = jsonObject.getString("catName");51 final String province = jsonObject.getString("province");52 showToastInAnyThread("运营商: "+catName+"\n归属地: "+province);53 } else{54 showToastInAnyThread("资源没有找到或者是服务器出了问题");55
56 }57 } catch(Exception e) {58 //TODO 自动生成的 catch 块
59 e.printStackTrace();60 showToastInAnyThread("访问失败");61
62 }63 };64 }.start();65 }66
67 public void showToastInAnyThread(finalString text) {68 runOnUiThread(newRunnable() {69 public voidrun() {70 Toast.makeText(MainActivity.this,text,0).show();71 };72 });73 }74
75
76 }
最后工程的一览图:
(5)布署程序到模拟器上运行效果如下图:
4.Jsonarray的使用
(1)新建一个Android工程"11_jsonArray",如下:
(2)首先我们设置一下UI界面,如下:
1
2 xmlns:tools="http://schemas.android.com/tools"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical"
6 tools:context="com.himi.jsonarray.MainActivity" >
7
8
10 android:layout_height="wrap_content"
11 android:orientation="horizontal" >
12
13
15 android:layout_height="wrap_content"
16 android:layout_marginLeft="5dip"
17 android:layout_marginTop="5dip"
18 android:layout_weight="1"
19 android:text="姓名:"
20 android:textAppearance="?android:attr/textAppearanceLarge"/>
21
22
24 android:layout_width="0dip"
25 android:layout_height="wrap_content"
26 android:layout_marginTop="5dip"
27 android:layout_weight="3" />
28
29
30
32 android:layout_height="wrap_content"
33 android:orientation="horizontal" >
34
35
37 android:layout_height="wrap_content"
38 android:layout_marginLeft="5dip"
39 android:layout_marginTop="5dip"
40 android:layout_weight="1"
41 android:text="年龄:"
42 android:textAppearance="?android:attr/textAppearanceLarge"/>
43
44
46 android:layout_width="0dip"
47 android:layout_height="wrap_content"
48 android:layout_marginTop="5dip"
49 android:layout_weight="3" />
50
51
52
54 android:layout_height="wrap_content"
55 android:orientation="horizontal" >
56
57
59 android:layout_height="wrap_content"
60 android:layout_marginLeft="5dip"
61 android:layout_marginTop="5dip"
62 android:layout_weight="1"
63 android:text="国籍:"
64 android:textAppearance="?android:attr/textAppearanceLarge"/>
65
66
68 android:layout_width="0dip"
69 android:layout_height="wrap_content"
70 android:layout_marginTop="5dip"
71 android:layout_weight="3" />
72
73
74
布局效果如下:
(3)MainActivity,如下:
1 packagecom.himi.jsonarray;2
3 importorg.json.JSONArray;4 importorg.json.JSONException;5 importorg.json.JSONObject;6
7 importandroid.app.Activity;8 importandroid.os.Bundle;9 importandroid.widget.TextView;10
11 public class MainActivity extendsActivity {12 privateTextView tv_name;13 privateTextView tv_age;14 privateTextView tv_country;15
16 private String jsonStr = "{carrier:'重庆移动'}";17 private String jsonArrStr = "[{name:'刘德华',age:'54',country:'中国'},"
18 + "{name:'梁朝伟',age:'53',country:'中国'},"
19 + "{name:'成龙',age:'61',country:'中国'}]";20 @Override21 protected voidonCreate(Bundle savedInstanceState) {22 super.onCreate(savedInstanceState);23 setContentView(R.layout.activity_main);24 tv_name =(TextView) findViewById(R.id.tv_name);25 tv_age =(TextView) findViewById(R.id.tv_age);26 tv_country =(TextView) findViewById(R.id.tv_country);27 try{28 JSONArray jsonArray = newJSONArray(jsonArrStr);29 for (int i = 0; i < 3; i++) {30 System.out.println(jsonArray.get(i).toString());31 }32 JSONObject jsonObject = new JSONObject(jsonArray.get(0).toString());33 String name = jsonObject.getString("name");34 String age = jsonObject.getString("age");35 String country = jsonObject.getString("country");36
37 tv_name.setText(name);38 tv_name.setTextSize(25);39 tv_age.setText(age);40 tv_age.setTextSize(25);41 tv_country.setText(country);42 tv_country.setTextSize(25);43 } catch(JSONException e) {44 //TODO 自动生成的 catch 块
45 e.printStackTrace();46 }47
48 }49
50
51 }
(4)布署程序到模拟器上,如下: