您的位置:首页 > 移动开发 > Android开发

一只大二狗的Android历程--JSon解析实例_天气预报

2017-03-16 20:44 495 查看
2017年3月17日 7:50 PM

一个月前我开了XML解析的坑到现在都没填完最后发现实在是没有时间搞这些老式的数据传输了,现在大部分都是使用轻量级的JSon来传输数据,这一星期看了JSon,感觉解析代码要比XML的要简洁不少,所以现在要说说解析JSon

JSON与XML的优缺点

JSON的优缺点

JSon的优点

  A.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;

  B.易于解析,客户端JavaScript可以简单的通过eval()进行JSON数据的读取;

  C.支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服务器端语言,便于服务器端的解析;

  D.在PHP世界,已经有PHP-JSON和JSON-PHP出现了,偏于PHP序列化后的程序直接调用,PHP服务器端的对象、数组等能直接生成JSON格式,便于客户端的访问提取;

  E.因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。

.JSON的缺点

  A.没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;

  B.JSON格式目前在Web Service中推广还属于初级阶段。

XML的优缺点

XML的优点

  A.格式统一,符合标准;

  B.容易与其他系统进行远程交互,数据共享比较方便。

XML的缺点

  A.XML文件庞大,文件格式复杂,传输占带宽;

  B.服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;

  C.客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;

  D.服务器端和客户端解析XML花费较多的资源和时间。

综上所述,还是选择JSON解析是主流所趋

JSON的格式

JSON两种格式,一种是键值对的形式,另一种是有序的类似数组的形式

无序键值对Object



如示意图,键值对是以 (key/value)对形式存在的无序的jsonObject对象,一个对象以“{”(左花括号)开始,“}”(右花括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。



这里的value的类型不限,可以是数组类型,也可以是另一个Object或者Bool类型的数据

有序数据Array



如示意图,这种是有序的value的集合,这种形式被称为是jsonArray,数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。

(修改自 JSON官网 http://www.json.org/json-zh.html

Android中提供的JSON解析类

Android给我们提供了一些解析JSON的类,这些类不需要再重复的导jar包来实现

JSONObject

可以看作是一个json对象,这是系统中有关JSON定义的基本单元,其包含一对儿(Key/Value)数值。它对外部(External: 应用toString()方法输出的数值)调用的响应体现为一个标准的字符串(例如:{“JSON”: “Hello, World”},最外被大括号包裹,其中的Key和Value被冒号”:”分隔)。其对于内部(Internal)行为的操作格式略微,例如:初始化一个JSONObject实例,引用内部的put()方法添加数值:new JSONObject().put(“JSON”, “Hello, World!”),在Key和Value之间是以逗号”,”分隔。Value的类型包括:Boolean、JSONArray、JSONObject、Number、String或者默认值JSONObject.NULL object 。

JSONStringer

json文本构建类 ,根据官方的解释,这个类可以帮助快速和便捷的创建JSON text。其最大的优点在于可以减少由于 格式的错误导致程序异常,引用这个类可以自动严格按照JSON语法规则(syntax rules)创建JSON text。每个JSONStringer实体只能对应创建一个JSON text。。其最大的优点在于可以减少由于格式的错误导致程序异常,引用这个类可以自动严格按照JSON语法规则(syntax rules)创建JSON text。每个JSONStringer实体只能对应创建一个JSON text。

JSONArray

它代表一组有序的数值。将其转换为String输出(toString)所表现的形式是用方括号包裹,数值以逗号”,”分隔(例如: [value1,value2,value3],大家可以亲自利用简短的代码更加直观的了解其格式)。这个类的内部同样具有查询行为, get()和opt()两种方法都可以通过index索引返回指定的数值,put()方法用来添加或者替换数值。同样这个类的value类型可以包括:Boolean、JSONArray、JSONObject、Number、String或者默认值 JSONObject.NULL object。

JSONTokener

json解析类

JSONException

json中用到的异常

了解到这里差不多就对JSON解析有一定的了解了,接下来就要通过一个实例—-天气预报来详细了解解析JSON工作的过程

JSON解析实例—-天气预报查询

该实例可以通过输入国内城市,县区的名称来实现

给大家提供一个免费API的接口,city=后面的城市可改

http://wthrcdn.etouch.cn/weather_mini?city=北京


获取JSON源代码

在进行解析JSON之前我们要先知道该API接口GET到的JSON数据是怎样的

{"desc":"OK","status":1000,"data":{"wendu":"5","ganmao":"昼夜温差较大,较易发生感冒,请适当增减衣服。体质较弱的朋友请注意防护。","forecast":[{"fengxiang":"南风","fengli":"微风级","high":"高温 17℃","type":"多云","low":"低温 6℃","date":"16日星期四"},{"fengxiang":"南风","fengli":"微风级","high":"高温 16℃","type":"阴","low":"低温 5℃","date":"17日星期五"},{"fengxiang":"南风","fengli":"微风级","high":"高温 19℃","type":"晴","low":"低温 4℃","date":"18日星期六"},{"fengxiang":"南风","fengli":"微风级","high":"高温 18℃","type":"晴","low":"低温 5℃","date":"19日星期天"},{"fengxiang":"东风","fengli":"微风级","high":"高温 15℃","type":"多云","low":"低温 5℃","date":"20日星期一"}],"yesterday":{"fl":"微风","fx":"南风","high":"高温 16℃","type":"多云","low":"低温 3℃","date":"15日星期三"},"aqi":"157","city":"北京"}}


JSON数据分析

你会发现这个JSON代码的可读性不是一般的差,所以我们拿到代码需要做的事就是“人肉解析”

{

"desc":"OK"

,"status":1000

<!--Data_Start_here(Type Obj)-->
,"data":
{

<!--Current_Tempreture -->
"wendu":"5"
<!--Wear_advice-->
,"ganmao":"昼夜温差较大,较易发生感冒,请适当增减衣服。体质较弱的朋友请注意防护。"
<!--Six_Days_Forecast(Type Array)-->
,"forecast":[
{"fengxiang":"南风","fengli":"微风级","high":"高温 17℃","type":"多云","low":"低温 6℃","date":"16日星期四"}
,{"fengxiang":"南风","fengli":"微风级","high":"高温 16℃","type":"阴","low":"低温 5℃","date":"17日星期五"}
,{"fengxiang":"南风","fengli":"微风级","high":"高温 19℃","type":"晴","low":"低温 4℃","date":"18日星期六"}
,{"fengxiang":"南风","fengli":"微风级","high":"高温 18℃","type":"晴","low":"低温 5℃","date":"19日星期天"}
,{"fengxiang":"东风","fengli":"微风级","high":"高温 15℃","type":"多云","low":"低温 5℃","date":"20日星期一"}
]
<!--Yesterday_Forecast-->
,"yesterday":{"fl":"微风","fx":"南风","high":"高温 16℃","type":"多云","low":"低温 3℃","date":"15日星期三"}
<!--API_NUM-->
,"aqi":"160"
<!--Current_City-->
,"city":"北京"

}
<!--Data_End_Here-->

}


这样就清晰多了,作为一个简单的天气查询,我们需要解析的数据是data key值下的数据,然后再次分离

"data":
{

<!--Current_Tempreture -->
"wendu":"5"
<!--Wear_advice-->
,"ganmao":"昼夜温差较大,较易发生感冒,请适当增减衣服。体质较弱的朋友请注意防护。"
<!--Six_Days_Forecast(Type Array)-->
,"forecast":[
{"fengxiang":"南风","fengli":"微风级","high":"高温 17℃","type":"多云","low":"低温 6℃","date":"16日星期四"}
,{"fengxiang":"南风","fengli":"微风级","high":"高温 16℃","type":"阴","low":"低温 5℃","date":"17日星期五"}
,{"fengxiang":"南风","fengli":"微风级","high":"高温 19℃","type":"晴","low":"低温 4℃","date":"18日星期六"}
,{"fengxiang":"南风","fengli":"微风级","high":"高温 18℃","type":"晴","low":"低温 5℃","date":"19日星期天"}
,{"fengxiang":"东风","fengli":"微风级","high":"高温 15℃","type":"多云","low":"低温 5℃","date":"20日星期一"}
]
<!--Yesterday_Forecast-->
,"yesterday":{"fl":"微风","fx":"南风","high":"高温 16℃","type":"多云","low":"低温 3℃","date":"15日星期三"}
<!--API_NUM-->
,"aqi":"160"
<!--Current_City-->
,"city":"北京"


这样我们就能发现,这个data下有四个键值对Object类型的数据(wendu,ganmao,city,yesterday)和一个Array类型的数据forecast,其中Array里又有6个Object类型的数据分别存储从今天开始的5天的天气数据,这样,分析完毕,我们就可以开始了写代码解析JSON数据了

代码部分

步骤1,建立布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<RelativeLayout
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<EditText
android:layout_marginLeft="20dp"
android:id="@+id/et"
android:hint="Please inout your city"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:layout_marginLeft="20dp"
android:layout_toEndOf="@+id/et"
android:id="@+id/getInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="GetWeatherInfo"
/>
<TextView
android:layout_margin="10dp"
android:textSize="25sp"
android:id="@+id/tv"
android:layout_below="@+id/getInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
</RelativeLayout>


步骤2,建立工具类(或者叫javaBean)weatherTools.java

public class weatherTools {
/**变量含义:
* Current_temp--->实时气温
* Advice---->衣着推荐
* City---->当前城市
* Wind_power---->风力
* Wind_dir---->风向
* Max---->最高气温
* Min---->最低气温
* Weather---->天气状况
* Date---->日期
*/
private String city;
private String current_temp;
private String max;
private String min;
private String weather;
private String wind_power;
private String wind_dir;
private String date;
private String advice;

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public String getCurrent_temp() {
return current_temp;
}

public void setCurrent_temp(String current_temp) {
this.current_temp = current_temp;
}

public String getMax() {
return max;
}

public void setMax(String max) {
this.max = max;
}

public String getMin() {
return min;
}

public void setMin(String min) {
this.min = min;
}

public String getWeather() {
return weather;
}

public void setWeather(String weather) {
this.weather = weather;
}

public String getDate() {
return date;
}

public void setDate(String date) {
this.date = date;
}

public String getWind_power() {
return wind_power;
}

public void setWind_power(String wind_power) {
this.wind_power = wind_power;
}

public String getWind_dir() {
return wind_dir;
}

public void setWind_dir(String wind_dir) {
this.wind_dir = wind_dir;
}

public String getAdvice() {
return advice;
}

public void setAdvice(String advice) {
this.advice = advice;
}
@Override
public String toString() {
return "当日天气预报:" +
"\n日期 " + date+
"\n城市 " + city  +
"\n天气 " + weather+
"\n衣着推荐 " + advice+
"\n实时气温" + current_temp +" ℃"+
"\n最高气温 " + max +
"\n最低气温 " + min +
"\n风力 " + wind_power +
"\n风向 " + wind_dir;
}

}


步骤3,建立获取Http服务器数据的类JSonFecher

import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/**
* Created by li124 on 2017/3/15.
*/

public class JSonFecher {
//这里是用来设置线程和存储获取数据
private String jsonText="";
//新建一个类用来获取JSon数据
public  String getJSONText(final URL url){
//新建线程
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
//新建输入流和内存存储Buffer
InputStream is =null;
BufferedReader in=null;
try{
//新建与http服务器的链接
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//设置超时时间
connection.setReadTimeout(10000);
connection.setConnectTimeout(15000);
//设置请求方式
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.connect();
//将使用输入流存储获取到的数据
is=connection.getInputStream();
//将数据写入内存
in=new BufferedReader(new InputStreamReader(is));
String line="null";
while ((line=in.readLine())!=null){
//从内存里提取数据赋值给jsonText
jsonText+=line;
}
//输出信息到控制台来确认数据是否收到
Log.i("-----------------",jsonText);
}catch (IOException e){
e.printStackTrace();
//关闭输入流来节省资源
}finally {
{
try{
in.close();
is.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
});
thread.start();

try{
//线程暂停
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
return jsonText;

}
}


步骤4,建立解析JSON文件的类JSonUtils

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URL;

/**
* Created by li124 on 2017/3/15.
*/

public class JSonUtils  {

public static weatherTools getWeatherTools(URL url){
//调用JSonFecher类获取从服务器的JSon数据
String jsonText =new JSonFecher().getJSONText(url);
//控制台输出获取的数据
System.out.println(jsonText);
//new一个weatherTools类的实例
weatherTools weatherTools=new weatherTools();
//以下代码为对JSon数据解析的操作
try{
//new 一个JSONObject,解析的是jsonText传的数据
JSONObject jsonObject=new JSONObject(jsonText);
//创建一个JSONObject  details 解析key值为data后的value
JSONObject detail=jsonObject.getJSONObject("data");
//创建temp,wear_advice,city来存储相应key值下的value
String temp=detail.getString("wendu");
String wear_advice=detail.getString("ganmao");
String city =detail.getString("city");
String fengli;
String fengxiang;
String max;
String weather;
String min;
String date;
//创建JSONArray来解析forecast下的数组中的数据
JSONArray ja=(JSONArray)detail.get("forecast");
//创建JSONObject来解析数组中各元素的数据,其中get(int Index)是用来确定解析元素的位置
//这里可以加上for循环加上ArrayList类型的数据来存储未来几天的天气数据,由于本人实用数据结构学的不怎么样所以这里只演示当天的天气数据= =
JSONObject jo=(JSONObject)ja.get(0);
fengli=jo.getString("fengli");
fengxiang=jo.getString("fengxiang");
max=jo.getString("high");
weather=jo.getString("type");
min=jo.getString("low");
date=jo.getString("date");
//这里对weatherTools里的变量进行赋值
/**变量含义:
* Current_temp--->实时气温
* Advice---->衣着推荐
* City---->当前城市
* Wind_power---->风力
* Wind_dir---->风向
* Max---->最高气温
* Min---->最低气温
* Weather---->天气状况
* Date---->日期
*/
weatherTools.setCurrent_temp(temp);
weatherTools.setAdvice(wear_advice);
weatherTools.setCity(city);
weatherTools.setWind_power(fengli);
weatherTools.setWind_dir(fengxiang);
weatherTools.setMax(max);
weatherTools.setMin(min);
weatherTools.setWeather(weather);
weatherTools.setDate(date);
}catch (JSONException e){
e.printStackTrace();
}
return weatherTools;
}
}


步骤5,MainActivity

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.net.URL;

public class MainActivity extends AppCompatActivity {
//    private static String url="http://www.weather.com.cn/data/cityinfo/101010100.html";
//上面的注释是用来访问中国天气网的API的,但是要想获取到本地的天气数据还要知道地区代码,所以不推荐
//下面的API是免费的没有申请次数,而且可以使用汉字作为关键字进行查询(感谢博主 crazyWangyb 的转载!)
public   String url="http://wthrcdn.etouch.cn/weather_mini?city=滨州";
Button button;
EditText et;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//指定控件
button=(Button) findViewById(R.id.getInfo);
et=(EditText)findViewById(R.id.et);
tv=(TextView)findViewById(R.id.tv);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//将在EditText获取到的文本与URL结合生成需要传递的URL进行访问查询
url="http://wthrcdn.etouch.cn/weather_mini?city="+et.getText().toString();
GetInfo(view);
}
});
}
public void GetInfo(View view){
try{
Log.i("----------",url);
URL u =new URL(url);
weatherTools weatherTools=JSonUtils.getWeatherTools(u);
System.out.println("TEXT2");
String message="";
message=weatherTools.toString();
tv.setText(message);
// message="Current Tempreture is :"+weatherTools.getCurrent_temp()+"\nYou should :"+weatherTools.getAdvice()+"\nCurrent city is :"+weatherTools.getCity()+"\nWind_power is :"+weatherTools.getWind_power()+"\nWind_dir is:"+weatherTools.getWind_dir();
System.out.println(message);
Toast.makeText(MainActivity.this,message,Toast.LENGTH_LONG).show();
}catch (Exception e){
e.printStackTrace();
}
}
}


写到这就写完了

效果图

由于我的虚拟机没办法装输入法,API又不认识拼音所以我直接用的实际测试的,只实现了核心功能,UI没有花心思设计,感觉有点丑啊 (¯﹃¯)





好了,写完了,这个JSON和XML好折磨人啊,特别是手动解析JSON的时候,分清楚到底是用JSONObject 还是 JSONArray花了我好长时间,,,对了还忘说了一件事,几个例子

注:

例子1: Array里面包含对象(object)

[ {“id”:1,”name”:”小猪” ,”age”:22} , {“id”:2,”name”:”小猫”,”age”:23} , …….]

例子2:同样对象(object)中可以包含Array

(1)一个对象包含1个数组,2个子对象

{“root”:[{“id”:”001”,”name”:”小猪”},{“id”:”002”,”name”:”小猫”},{“id”:”003”,”name”:”小狗”}],

“total”:3,

“success”:true

}

(2)也可以对象嵌套子对象,子对象再嵌套数组

{“calendar”:

{“calendarlist”:

[

{“id”:”001”,”name”:”小猪”},

{“id”:”002”,”name”:”小猫”}

]

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android