Android 基础总结:( 二十三)JSON详解(下)

来自Google官方的有关Android平台的JSON解析示例,如果远程服务器使用了json而不是xml的数据提供,在Android平台上已经内置的org.json包可以很方便的实现手机客户端的解析处理。下面一起分析下这个例子,帮助Android开发者需要有关HTTP通讯、正则表达式、JSON解析、appWidget开发的一些知识。


示例一

[java]  view plain  copy
 print ?
  1. public class WordWidget extends AppWidgetProvider { // appWidget  
  2.     @Override  
  3.     public void onUpdate(Context context, AppWidgetManager appWidgetManager,  
  4.             int[] appWidgetIds) {  
  5.         context.startService(new Intent(context, UpdateService.class)); // 避免ANR,所以Widget中开了个服务  
  6.     }  
  7.     public static class UpdateService extends Service {  
  8.         @Override  
  9.         public void onStart(Intent intent, int startId) {  
  10.             // Build the widget update for today  
  11.             RemoteViews updateViews = buildUpdate(this);  
  12.             ComponentName thisWidget = new ComponentName(this, WordWidget.class);  
  13.             AppWidgetManager manager = AppWidgetManager.getInstance(this);  
  14.             manager.updateAppWidget(thisWidget, updateViews);  
  15.         }  
  16.         public RemoteViews buildUpdate(Context context) {  
  17.             // Pick out month names from resources  
  18.             Resources res = context.getResources();  
  19.             String[] monthNames = res.getStringArray(R.array.month_names);  
  20.             Time today = new Time();  
  21.             today.setToNow();  
  22.             String pageName = res.getString(R.string.template_wotd_title,  
  23.                     monthNames[today.month], today.monthDay);  
  24.             RemoteViews updateViews = null;  
  25.             String pageContent = "";  
  26.             try {  
  27.                 SimpleWikiHelper.prepareUserAgent(context);  
  28.                 pageContent = SimpleWikiHelper.getPageContent(pageName, false);  
  29.             } catch (ApiException e) {  
  30.                 Log.e("WordWidget""Couldn't contact API", e);  
  31.             } catch (ParseException e) {  
  32.                 Log.e("WordWidget""Couldn't parse API response", e);  
  33.             }  
  34.             Pattern pattern = Pattern  
  35.                     .compile(SimpleWikiHelper.WORD_OF_DAY_REGEX); // 正则表达式处理,有关定义见下面的SimpleWikiHelper类  
  36.             Matcher matcher = pattern.matcher(pageContent);  
  37.             if (matcher.find()) {  
  38.                 updateViews = new RemoteViews(context.getPackageName(),  
  39.                         R.layout.widget_word);  
  40.                 String wordTitle = matcher.group(1);  
  41.                 updateViews.setTextViewText(R.id.word_title, wordTitle);  
  42.                 updateViews.setTextViewText(R.id.word_type, matcher.group(2));  
  43.                 updateViews.setTextViewText(R.id.definition, matcher.group(3)  
  44.                         .trim());  
  45.                 String definePage = res.getString(R.string.template_define_url,  
  46.                         Uri.encode(wordTitle));  
  47.                 Intent defineIntent = new Intent(Intent.ACTION_VIEW,  
  48.                         Uri.parse(definePage)); // 这里是打开相应的网页,所以Uri是http的url,action是view即打开web浏览器  
  49.                 PendingIntent pendingIntent = PendingIntent.getActivity(  
  50.                         context, 0 /* no requestCode */, defineIntent, 0 /* 
  51.                                                                          * no 
  52.                                                                          * flags 
  53.                                                                          */);  
  54.                 updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent); // 单击Widget打开Activity  
  55.             } else {  
  56.                 updateViews = new RemoteViews(context.getPackageName(),  
  57.                         R.layout.widget_message);  
  58.                 CharSequence errorMessage = context  
  59.                         .getText(R.string.widget_error);  
  60.                 updateViews.setTextViewText(R.id.message, errorMessage);  
  61.             }  
  62.             return updateViews;  
  63.         }  
  64.         @Override  
  65.         public IBinder onBind(Intent intent) {  
  66.             // We don't need to bind to this service  
  67.             return null;  
  68.         }  
  69.     }  
  70. }  
有关网络通讯的实体类,以及一些常量定义如下:

[java]  view plain  copy
 print ?
  1. public class SimpleWikiHelper {  
  2.     private static final String TAG = "SimpleWikiHelper";  
  3.     public static final String WORD_OF_DAY_REGEX = "(?s)\\{\\{wotd\\|(.+?)\\|(.+?)\\|([^\\|]+).*?\\}\\}";  
  4.     private static final String WIKTIONARY_PAGE = "http://en.wiktionary.org/w/api.php?action=query&prop=revisions&titles=%s&  
  5.             + "rvprop=content&format=json%s";  
  6.     private static final String WIKTIONARY_EXPAND_TEMPLATES = "&rvexpandtemplates=true";  
  7.     private static final int HTTP_STATUS_OK = 200;  
  8.     private static byte[] sBuffer = new byte[512];  
  9.     private static String sUserAgent = null;  
  10.     public static class ApiException extends Exception {  
  11.         public ApiException(String detailMessage, Throwable throwable) {  
  12.             super(detailMessage, throwable);  
  13.         }  
  14.         public ApiException(String detailMessage) {  
  15.             super(detailMessage);  
  16.         }  
  17.     }  
  18.     public static class ParseException extends Exception {  
  19.         public ParseException(String detailMessage, Throwable throwable) {  
  20.             super(detailMessage, throwable);  
  21.         }  
  22.     }  
  23.     public static void prepareUserAgent(Context context) {  
  24.         try {  
  25.             // Read package name and version number from manifest  
  26.             PackageManager manager = context.getPackageManager();  
  27.             PackageInfo info = manager.getPackageInfo(context.getPackageName(),  
  28.                     0);  
  29.             sUserAgent = String.format(  
  30.                     context.getString(R.string.template_user_agent),  
  31.                     info.packageName, info.versionName);  
  32.         } catch (NameNotFoundException e) {  
  33.             Log.e(TAG, "Couldn't find package information in PackageManager", e);  
  34.         }  
  35.     }  
  36.     public static String getPageContent(String title, boolean expandTemplates)  
  37.             throws ApiException, ParseException {  
  38.         String encodedTitle = Uri.encode(title);  
  39.         String expandClause = expandTemplates ? WIKTIONARY_EXPAND_TEMPLATES  
  40.                 : "";  
  41.         String content = getUrlContent(String.format(WIKTIONARY_PAGE,  
  42.                 encodedTitle, expandClause));  
  43.         try {  
  44.             JSONObject response = new JSONObject(content);  
  45.             JSONObject query = response.getJSONObject("query");  
  46.             JSONObject pages = query.getJSONObject("pages");  
  47.             JSONObject page = pages.getJSONObject((String) pages.keys().next());  
  48.             JSONArray revisions = page.getJSONArray("revisions");  
  49.             JSONObject revision = revisions.getJSONObject(0);  
  50.             return revision.getString("*");  
  51.         } catch (JSONException e) {  
  52.             throw new ParseException("Problem parsing API response", e);  
  53.         }  
  54.     }  
  55.     protected static synchronized String getUrlContent(String url)  
  56.             throws ApiException {  
  57.         if (sUserAgent == null) {  
  58.             throw new ApiException("User-Agent string must be prepared");  
  59.         }  
  60.         HttpClient client = new DefaultHttpClient();  
  61.         HttpGet request = new HttpGet(url);  
  62.         request.setHeader("User-Agent", sUserAgent); // 设置客户端标识  
  63.         try {  
  64.             HttpResponse response = client.execute(request);  
  65.             StatusLine status = response.getStatusLine();  
  66.             if (status.getStatusCode() != HTTP_STATUS_OK) {  
  67.                 throw new ApiException("Invalid response from server:   
  68.                         + status.toString());  
  69.             }  
  70.             HttpEntity entity = response.getEntity();  
  71.             InputStream inputStream = entity.getContent(); // 获取HTTP返回的数据流  
  72.             ByteArrayOutputStream content = new ByteArrayOutputStream();  
  73.             int readBytes = 0;  
  74.             while ((readBytes = inputStream.read(sBuffer)) != -1) {  
  75.                 content.write(sBuffer, 0, readBytes); // 转化为字节数组流  
  76.             }  
  77.             return new String(content.toByteArray()); // 从字节数组构建String  
  78.         } catch (IOException e) {  
  79.             throw new ApiException("Problem communicating with API", e);  
  80.         }  
  81.     }  
  82. }  
有关整个每日维基的widget例子比较简单,主要是帮助大家积累常用代码,了解Android平台 JSON的处理方式,毕竟很多Server还是Java的。


示例二

[java]  view plain  copy
 print ?
  1. public class JSON {  
  2.     /** 
  3.      * 获取"数组形式"的JSON数据, 数据形式:[{"id":1,"name":"小猪"},{"id":2,"name":"小猫"}] 
  4.      *  
  5.      * @param path 
  6.      *            网页路径 
  7.      * @return 返回List 
  8.      * @throws Exception 
  9.      */  
  10.     public static List<Map<String, String>> getJSONArray(String path)  
  11.             throws Exception {  
  12.         String json = null;  
  13.         List<Map<String, String>> list = new ArrayList<Map<String, String>>();  
  14.         Map<String, String> map = null;  
  15.         URL url = new URL(path);  
  16.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 利用HttpURLConnection对象,我们可以从网络中获取网页数据.  
  17.         conn.setConnectTimeout(5 * 1000); // 单位是毫秒,设置超时时间为5秒  
  18.         conn.setRequestMethod("GET"); // HttpURLConnection是通过HTTP协议请求path路径的,所以需要设置请求方式,可以不设置,因为默认为GET  
  19.         if (conn.getResponseCode() == 200) {// 判断请求码是否是200码,否则失败  
  20.             InputStream is = conn.getInputStream(); // 获取输入流  
  21.             byte[] data = readStream(is); // 把输入流转换成字符数组  
  22.             json = new String(data); // 把字符数组转换成字符串  
  23.             // 数据形式:[{"id":1,"name":"小猪","age":22},{"id":2,"name":"小猫","age":23}]  
  24.             JSONArray jsonArray = new JSONArray(json); // 数据直接为一个数组形式,所以可以直接  
  25.                                                         // 用android提供的框架JSONArray读取JSON数据,转换成Array  
  26.             for (int i = 0; i < jsonArray.length(); i++) {  
  27.                 JSONObject item = jsonArray.getJSONObject(i); // 每条记录又由几个Object对象组成  
  28.                 int id = item.getInt("id"); // 获取对象对应的值  
  29.                 String name = item.getString("name");  
  30.                 map = new HashMap<String, String>(); // 存放到MAP里面  
  31.                 map.put("id", id + "");  
  32.                 map.put("name", name);  
  33.                 list.add(map);  
  34.             }  
  35.         }  
  36.         // ***********测试数据******************  
  37.         for (Map<String, String> list2 : list) {  
  38.             String id = list2.get("id");  
  39.             String name = list2.get("name");  
  40.             Log.i("abc""id:" + id + " | name:" + name);  
  41.         }  
  42.         return list;  
  43.     }  
  44.     /** 
  45.      * 获取"对象形式"的JSON数据, 
  46.      * 数据形式:{"total":2,"success":true,"arrayData":[{"id":1,"name" 
  47.      * :"小猪"},{"id":2,"name":"小猫"}]} 
  48.      *  
  49.      * @param path 
  50.      *            网页路径 
  51.      * @return 返回List 
  52.      * @throws Exception 
  53.      */  
  54.     public static List<Map<String, String>> getJSONObject(String path)  
  55.             throws Exception {  
  56.         List<Map<String, String>> list = new ArrayList<Map<String, String>>();  
  57.         Map<String, String> map = null;  
  58.         URL url = new URL(path);  
  59.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 利用HttpURLConnection对象,我们可以从网络中获取网页数据.  
  60.         conn.setConnectTimeout(5 * 1000); // 单位是毫秒,设置超时时间为5秒  
  61.         conn.setRequestMethod("GET"); // HttpURLConnection是通过HTTP协议请求path路径的,所以需要设置请求方式,可以不设置,因为默认为GET  
  62.         if (conn.getResponseCode() == 200) {// 判断请求码是否是200码,否则失败  
  63.             InputStream is = conn.getInputStream(); // 获取输入流  
  64.             byte[] data = readStream(is); // 把输入流转换成字符数组  
  65.             String json = new String(data); // 把字符数组转换成字符串  
  66.             // 数据形式:{"total":2,"success":true,"arrayData":[{"id":1,"name":"小猪"},{"id":2,"name":"小猫"}]}  
  67.             JSONObject jsonObject = new JSONObject(json); // 返回的数据形式是一个Object类型,所以可以直接转换成一个Object  
  68.             int total = jsonObject.getInt("total");  
  69.             Boolean success = jsonObject.getBoolean("success");  
  70.             Log.i("abc""total:" + total + " | success:" + success); // 测试数据  
  71.             JSONArray jsonArray = jsonObject.getJSONArray("arrayData");// 里面有一个数组数据,可以用getJSONArray获取数组  
  72.             for (int i = 0; i < jsonArray.length(); i++) {  
  73.                 JSONObject item = jsonArray.getJSONObject(i); // 得到每个对象  
  74.                 int id = item.getInt("id"); // 获取对象对应的值  
  75.                 String name = item.getString("name");  
  76.                 map = new HashMap<String, String>(); // 存放到MAP里面  
  77.                 map.put("id", id + "");  
  78.                 map.put("name", name);  
  79.                 list.add(map);  
  80.             }  
  81.         }  
  82.         // ***********测试数据******************  
  83.         for (Map<String, String> list2 : list) {  
  84.             String id = list2.get("id");  
  85.             String name = list2.get("name");  
  86.             Log.i("abc""id:" + id + " | name:" + name);  
  87.         }  
  88.         return list;  
  89.     }  
  90.     /** 
  91.      * 获取类型复杂的JSON数据 数据形式: {"name":"小猪", "age":23, 
  92.      * "content":{"questionsTotal":2, "questions": [ { "question": 
  93.      * "what's your name?", "answer": "小猪"},{"question": "what's your age", 
  94.      * "answer": "23"}] } } 
  95.      *  
  96.      * @param path 
  97.      *            网页路径 
  98.      * @return 返回List 
  99.      * @throws Exception 
  100.      */  
  101.     public static List<Map<String, String>> getJSON(String path)  
  102.             throws Exception {  
  103.         List<Map<String, String>> list = new ArrayList<Map<String, String>>();  
  104.         Map<String, String> map = null;  
  105.         URL url = new URL(path);  
  106.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 利用HttpURLConnection对象,我们可以从网络中获取网页数据.  
  107.         conn.setConnectTimeout(5 * 1000); // 单位是毫秒,设置超时时间为5秒  
  108.         conn.setRequestMethod("GET"); // HttpURLConnection是通过HTTP协议请求path路径的,所以需要设置请求方式,可以不设置,因为默认为GET  
  109.         if (conn.getResponseCode() == 200) {// 判断请求码是否是200码,否则失败  
  110.             InputStream is = conn.getInputStream(); // 获取输入流  
  111.             byte[] data = readStream(is); // 把输入流转换成字符数组  
  112.             String json = new String(data); // 把字符数组转换成字符串  
  113.             /* 
  114.              * 数据形式: {"name":"小猪", "age":23, "content":{"questionsTotal":2, 
  115.              * "questions": [ { "question": "what's your name?", "answer": 
  116.              * "小猪"},{"question": "what's your age", "answer": "23"}] } } 
  117.              */  
  118.             JSONObject jsonObject = new JSONObject(json); // 返回的数据形式是一个Object类型,所以可以直接转换成一个Object  
  119.             String name = jsonObject.getString("name");  
  120.             int age = jsonObject.getInt("age");  
  121.             Log.i("abc""name:" + name + " | age:" + age); // 测试数据  
  122.             JSONObject contentObject = jsonObject.getJSONObject("content"); // 获取对象中的对象  
  123.             String questionsTotal = contentObject.getString("questionsTotal"); // 获取对象中的一个值  
  124.             Log.i("abc""questionsTotal:" + questionsTotal); // 测试数据  
  125.             JSONArray contentArray = contentObject.getJSONArray("questions"); // 获取对象中的数组  
  126.             for (int i = 0; i < contentArray.length(); i++) {  
  127.                 JSONObject item = contentArray.getJSONObject(i); // 得到每个对象  
  128.                 String question = item.getString("question"); // 获取对象对应的值  
  129.                 String answer = item.getString("answer");  
  130.                 map = new HashMap<String, String>(); // 存放到MAP里面  
  131.                 map.put("question", question);  
  132.                 map.put("answer", answer);  
  133.                 list.add(map);  
  134.             }  
  135.         }  
  136.         // ***********测试数据******************  
  137.         for (Map<String, String> list2 : list) {  
  138.             String question = list2.get("question");  
  139.             String answer = list2.get("answer");  
  140.             Log.i("abc""question:" + question + " | answer:" + answer);  
  141.         }  
  142.         return list;  
  143.     }  
  144.     /** 
  145.      * 把输入流转换成字符数组 
  146.      *  
  147.      * @param inputStream 
  148.      *            输入流 
  149.      * @return 字符数组 
  150.      * @throws Exception 
  151.      */  
  152.     public static byte[] readStream(InputStream inputStream) throws Exception {  
  153.         ByteArrayOutputStream bout = new ByteArrayOutputStream();  
  154.         byte[] buffer = new byte[1024];  
  155.         int len = 0;  
  156.         while ((len = inputStream.read(buffer)) != -1) {  
  157.             bout.write(buffer, 0, len);  
  158.         }  
  159.         bout.close();  
  160.         inputStream.close();  
  161.         return bout.toByteArray();  
  162.     }  
  163. }  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值