在前面两篇博客《Android之Http网络编程(一)》、《Android之Http网络编程(二)》中,简单的介绍了对网页的请求和客户端与服务端的简单的参数交互。那么,这一篇博客就来认识一下Android客户端获取服务端返回的数据。
大家都知道客户端与服务端的交互大体过程如下:
- Android客户端向服务器发出请求。
- 服务端接收请求并响应。
- 服务端返回数据给客户端。
对于Android客户端来说,最重要的也就莫过于获取服务端返回的数据来展示了。
那么,首先我们要知道服务端返回的数据格式是什么?(因为对于服务端返回的数据内容,我们只需要完完整整呈现即可。因此,更重要的就是数据的格式了,因为不同的数据格式获取数据的方式会稍有不同。)最常见的数据格式有:JSON和XML两种。(这两种数据格式的优劣,请参考文章《JSON与XML的区别比较》)对于后者,XML的解析方式有三种:pull解析、sax解析、dom解析。个人认为PULL解析最简单,详情请看另一篇博客《Android XML解析》(这里只有PULL解析,找时间我把另外两种也写上)
这篇博客,我们重点来学习从服务器端返回JSON格式的数据。
JSON格式的数据分为两种,一种是JSON对象,另一种是JSON对象数组。
下面我们分别来实现:
我们先实现获取JSON对象。
我们将下面的JSON字符串复制到一个新建的文本文件(就是记事本打开的那个)中,取名为“testjson”,将后缀改为.json。
{"PubId":"001","PubTitle":"testContent","PubTime":"2014-9-30 12:01:13","PubAuthor":"Admin"}
并将该文件放在Tomcat的文件路径下(我放的路径是E:编程软件及工具 omcatapache-tomcat-7.0.55webappsROOTmytest),对Tomcat不熟悉的话请看博客《Android中Tomcat的简单配置和使用》。
放在Tomcat文件下后,启动Tomcat服务,在在浏览器中输入访问地址:http://127.0.0.1:8080/mytest/testjson.json
得到如下结果:
这就是通过浏览器查看我们需要获得的JSON格式的数据。
下面我们用代码来实现:
(方便起见,直接在启动Activity时就访问,并输出数据返回结果)
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getData(); } private void getData() { new Thread(new Runnable() { @Override public void run() { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet( "http://192.168.1.101:8080/mytest/testjson.json"); HttpResponse response; try { response = client.execute(get); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String str = EntityUtils.toString(response.getEntity()); //将返回的字符串转换成JSON对象 JSONObject json = new JSONObject(str); //获取JSON对象的标签关键字对应的值 String id = json.getString("PubId"); String title = json.getString("PubTitle"); String author = json.getString("PubAuthor"); String time = json.getString("PubTime"); //输出JSON对象的值 System.out.println("id:" + id); System.out.println("title:" + title); System.out.println("author:" + author); System.out.println("time:" + time); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } }
注意:在Android4.0之后不能在主线程中访问网络,记得在清单文件中添加网络访问权限:<uses-permission android:name="android.permission.INTERNET" />
运行程序,结果如下:
这样,我们就获取到了从服务器端返回的JSON格式的数据了,是不是很简单。
接下来我们实现获取JSON对象数组。其实和上面获取JSON对象相似。
将JSON对象数据源换成JSON对象数组,如下:
[{"PubId":"001","PubTitle":"test1","PubTime":"2014-9-30 12:01:13","PubAuthor":"Admin"},{"PubId":"002","PubTitle":"test2","PubTime":"2014-9-31 12:01:13","PubAuthor":"Admin"},{"PubId":"003","PubTitle":"test3","PubTime":"2014-9-31","PubAuthor":"Admin"}]
接下来的操作和获取JSON对象相同。
我们在浏览器中查看:
获取json对象数组的代码实现:
private void getData() { new Thread(new Runnable() { @Override public void run() { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet( "http://192.168.1.101:8080/mytest/testjsonArray.json"); HttpResponse response; try { response = client.execute(get); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String str = EntityUtils.toString(response.getEntity()); // 将返回的字符串转换成JSON对象数组 JSONArray jsonArray = new JSONArray(str); for (int i = 0; i < jsonArray.length(); i++) {
//获取JSON数组中的某一具体JSON对象 JSONObject json = jsonArray.getJSONObject(i); // 获取JSON对象的标签关键字对应的值 String id = json.getString("PubId"); String title = json.getString("PubTitle"); String author = json.getString("PubAuthor"); String time = json.getString("PubTime"); // 输出JSON对象的值 System.out.println("id:" + id); System.out.println("title:" + title); System.out.println("author:" + author); System.out.println("time:" + time); System.out .println("----------------华丽的分割线---------------------"); } } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); }
运行结果如下:
OK,现在获取JSON格式数据的常用操作就完了。
其实,如果是JSON的话,也可以使用第三方包来解析并获取数据,更加方便快捷。比如:Gson包(需要有相对应的实体类)。
GSON的下载地址:https://code.google.com/p/google-gson/downloads/list?can=1&q
打开网址后下载2.2.4版(目前最新版)
下载后解压压缩包,有如下文件:
其中gson-2.2.4.jar就是我们所需要的。将其添加到项目的libs文件夹下,并添加到项目中。
设置实体类为:
public class Entity { //字段应与返回的JSON格式数据的关键字相同 private String PubId; private String PubTitle; private String PubTime; private String PubAuthor; public String getPubId() { return PubId; } public void setPubId(String pubId) { PubId = pubId; } public String getPubTitle() { return PubTitle; } public void setPubTitle(String pubTitle) { PubTitle = pubTitle; } public String getPubTime() { return PubTime; } public void setPubTime(String pubTime) { PubTime = pubTime; } public String getPubAuthor() { return PubAuthor; } public void setPubAuthor(String pubAuthor) { PubAuthor = pubAuthor; } }
以上面实例返回的json格式的数据为例,如果返回的是一个JSON对象,则需要代码:
Gson gson=new Gson(); Entity entity=gson.fromJson(str, Entity.class); Log.e("Gson", entity.getPubId()); Log.e("Gson", entity.getPubTitle()); Log.e("Gson", entity.getPubAuthor()); Log.e("Gson", entity.getPubTime());
即可打印出获取到的JSON对象数据。
如果返回的是一个JSON对象数组,则代码为:
Gson gson=new Gson(); //获取一个JSON对象数组 List<Entity> entitylist=gson.fromJson(str, new TypeToken<List<Entity>>(){}.getType()); for(Entity entity:entitylist){ Log.d("Gson jsonArray", entity.getPubId()); Log.d("Gson jsonArray", entity.getPubTitle()); Log.d("Gson jsonArray", entity.getPubAuthor()); Log.d("Gson jsonArray", entity.getPubTime()); }
即可打印出返回的JSON对象数组。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); testGson(); } public void testGson() { new Thread(new Runnable() { private String str; @Override public void run() { HttpClient client = new DefaultHttpClient(); // 设置路径 // HttpPost request = new HttpPost( // "http://172.27.35.9:8080/mytest/testjson.json"); HttpPost request = new HttpPost( "http://172.27.35.9:8080/mytest/testjsonArray.json"); HttpResponse response; try { response = client.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { str = EntityUtils.toString(response.getEntity(),"GBK").trim(); parseToJson(str); } else { str = "请求失败"; } System.out.println(str);// 打印返回结果 } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } protected void parseToJson(String str) { Gson gson=new Gson(); //获取一个JSON对象数组 List<Entity> entitylist=gson.fromJson(str, new TypeToken<List<Entity>>(){}.getType()); for(Entity entity:entitylist){ Log.d("Gson jsonArray", entity.getPubId()); Log.d("Gson jsonArray", entity.getPubTitle()); Log.d("Gson jsonArray", entity.getPubAuthor()); Log.d("Gson jsonArray", entity.getPubTime()); } //获取一个JSON对象 // Gson gson=new Gson(); // Entity entity=gson.fromJson(str, Entity.class); // Log.e("Gson", entity.getPubId()); // Log.e("Gson", entity.getPubTitle()); // Log.e("Gson", entity.getPubAuthor()); // Log.e("Gson", entity.getPubTime()); } }
运行程序,结果如下:
获取到的一个JSON对象:
获取到的JSON对象数组:
获取JSON格式数据的操作,总体上还是比较简单,就不附上DEMO了。
注意:如果要将获取到的网络数据添加到界面上,需要使用到Android的异步消息处理机制。因为对网络的操作属于耗时操作,为了不阻塞主线程我们一般新开一个新的线程来执行网络请求。然而,只有主线程(即UI线程)可以更新界面,因此我们获取的网络数据通过异步消息处理机制从子线程传递到主线程,并最终实现更新UI。
对异步消息处理机制不熟悉的话 ,可以参考另外两篇博文《Android线程与异步消息处理机制》、《Android 在子线程中更新UI》。