当前位置: 代码迷 >> Android >> android天气预报应用(2)
  详细解决方案

android天气预报应用(2)

热度:11   发布时间:2016-04-28 06:40:56.0
android天气预报应用(二)

接上一篇博文。http://blog.csdn.net/icedcap/article/details/20743627

上一篇博文稍微开了个头,没想到很多朋友都很感兴趣催我继续往下写。今天挤出点时间为大家继续介绍。

    在进入真题之前,笔者还是想要吐槽以下中国气象局。事情是这样的,笔者申请的是android和ios平台的接口,而他却给我的web端的接口。笔者回信询问他却说统一发放web端的appid和private_key。既然你光给开发者web端的,你何必在官网介绍移动端介绍的那么好还给了那么详细的文档呢?要是知道你仅给个web端的,我还不如省去麻烦用其他不需要appid和private_key的web接口呢!鄙视

   好了,唠叨就那么多,现在进入正题。

一、官方文档使用说明

    以下是文档中的原话,copy过来。

1、产品概述
    SmartWeatherAPI 接口(简称”SWA”接口)是中国气象局面向网络媒体、手机厂商、第三方气象服务机构等用户,通过 web 方式提供数据气象服务的官方载体。
2、使用说明

    该数据主要包括实况、指数、常规预报等数据内容。
3、调用规范
    规范用于指导开放平台用户合理调用实况、指数、常规预报等服务数据。
    请求方式:http get
    接口组成:由固定 URL 加 5 个不同的参数组成,完整 URL 需客户端经过固定方式加密后使用。
    数据返回:json
    完整 URL:http://webapi.weather.com.cn/data/?areaid=""&type=""&date=""&appid=""&key=".urlencode($key);

注意:这里的appid只取字符串的前六位。
    固定 URL:http://webapi.weather.com.cn/data/



这里边的难点就在于请求URL的最后一个参数key=".urlencode($key),它是一个通过php的函数算出来的。具体如下:

加密方式:
    private_key 仅负责与 public_key 共同合成 key 传参,私钥不可见,客户端与服务端各存储一份;

    public_key 为不包含 key 在内的完整 URL 其它部分(此处appid 为完整 appid)
示例:
http://webapi.weather.com.cn/data/?areaid=101010100&type=forecast&date=201211281030&appid= cf2d61521456sads
key 的算法
key=base64_encode(hash_hmac('sha1',$public_key,$private_key,TRUE));
key 加密后通过 urlencode 对其编码后传参
注:每一个产品使用用户分配一个唯一标识 appid,用于统计用户访问情况、区分用户提供差异服务,终端用户按照终端型号分配,一个型号对应一个标识。

由于key的算法在web端开发是十分顺手的,只需要将上面那串代码写到php中就OK了,然而将上述算法迁徙到java中还是费了笔者不少的功夫,这里笔者将无私的分享给大家。具体代码如下:

	/**	 * 计算签名	 * @param baseString 明文	 * @param keyString 私钥	 * @return 秘钥	 * @throws GeneralSecurityException	 * @throws UnsupportedEncodingException	 */	public static String computeSignature(String baseString, String keyString)			throws GeneralSecurityException, UnsupportedEncodingException {		SecretKey secretKey = null;		byte[] keyBytes = keyString.getBytes();		secretKey = new SecretKeySpec(keyBytes, "HmacSHA1");		Mac mac = Mac.getInstance("HmacSHA1");		mac.init(secretKey);		byte[] text = baseString.getBytes();		return new String(Base64.encodeBase64(mac.doFinal(text))).trim();	}

二、JSON解析

突破了秘钥的难关就已经完成了一半了。下面笔者将介绍如何解析的得到的JSON数据。

这里将拿得到的实时天气数据来解释。数据如下:

{"l":{"l1":"8","l2":"35","l3":"2","l4":"2","l7":"15:30"}}

很简单,对JSON没什么概念的就可以直接理解成第一个l代表引用在它冒号后面的是他的对象,其中对象中的l1,l2,l3,l4,l7分别是对象的不同属性,在API中这几个属性分别代表“当前温度”、“当前湿度”、“当前风力”、“当前风向”、“发布时间”。

    代码如下:

JSONObject obj = new JSONObject(bufferString.trim()).getJSONObject("l");
String currentTemperature = obj.getString("l1");String currentHumidity = obj.getString("l2");String currentWindForce = obj.getString("l3");String currentWindDirectionNumber = obj.getString("l4");

这是最简单的一种JSON数据格式,在该应用中你还会发现如下结构的JSON。

{"f1":[{"fg":"","ff":"0","fi":"06:34|18:15","fh":"0","fa":"","fd":"2","fe":"","fb":"53","fc":""},{"fg":"0","ff":"8","fi":"06:32|18:16","fh":"1","fa":"02","fd":"3","fe":"0","fb":"07","fc":"12"},{"fg":"0","ff":"0","fi":"06:30|18:17","fh":"0","fa":"00","fd":"-2","fe":"0","fb":"00","fc":"10"}]

}

这种结构也可以用对象的概念说通只不过对象变成了对象数组。

   这里的f1代表的三天内的天气情况,天气具体情况存入了数组中解析的时候要用如下代码:

JSONArray forecast = forecast3d.getJSONArray("f1");

String[] dayWeatherPhenomenonNumber = new String[forecast.length()];String[] nightWeatherPhenomenonNumber = new String[forecast						.length()];String[] maxTemperature = new String[forecast.length()];String[] minTemperature = new String[forecast.length()];String[] dayWindDirectionNumber = new String[forecast.length()];String[] nightWindDirectionNumber = new String[forecast.length()];String[] dayWindForce = new String[forecast.length()];String[] nightWindForce = new String[forecast.length()];String[] dayWindDirection = new String[forecast.length()];String[] nightWindDirection = new String[forecast.length()];String[] dayWeatherPhenomenon = new String[forecast.length()];String[] nightWeatherPhenomenon = new String[forecast.length()];String forecast3dMsg[] = new String[forecast.length()];for (int i = 0; i < forecast.length(); i++) {	JSONObject forecastObj = (JSONObject) forecast.opt(i);	dayWeatherPhenomenonNumber[i] = forecastObj.getString("fa");// 白天天气现象编号	nightWeatherPhenomenonNumber[i] = forecastObj.getString("fb");// 夜晚天气现象编号	System.out.println("day气象编号----》"+ dayWeatherPhenomenonNumber[i]);	dayWeatherPhenomenon[i] = Util.getWeatherPhenomenon(dayWeatherPhenomenonNumber[i]);	System.out.println("night气象编号----》"+ nightWeatherPhenomenonNumber[i]);	nightWeatherPhenomenon[i] = Util.getWeatherPhenomenon(nightWeatherPhenomenonNumber[i]);// 具体天气现象	maxTemperature[i] = forecastObj.getString("fc");	minTemperature[i] = forecastObj.getString("fd");// 气温	dayWindDirectionNumber[i] = forecastObj.getString("fe");	nightWindDirectionNumber[i] = forecastObj.getString("ff");// 风向编号	dayWindDirection[i] = Util.getWindDirection(dayWindDirectionNumber[i]);	nightWindDirection[i] = Util.getWindDirection(nightWindDirectionNumber[i]);// 具体风向	dayWindForce[i] = forecastObj.getString("fg");	nightWindForce[i] = forecastObj.getString("fh");// 风力	forecast3dMsg[i] = "\n第" + (i + 1) + "天:  " + "白天:"				+ dayWeatherPhenomenon[i] + " "				+ dayWindDirection[i] + dayWindForce[i] + "级\n"				+ " 		夜晚:" + nightWeatherPhenomenon[i] + " "				+ nightWindDirection[i] + nightWindForce[i]				+ "级  气温:" + minTemperature[i] + "~"				+ maxTemperature[i] + "℃";	System.out.println(forecast3dMsg);}

好了,今天先说这么多吧。下一篇博客,将介绍http异步加载的优化。

由于有朋友留言要代码,那我就先贴出没优化过的代码:
http://download.csdn.net/detail/icedcap/7019893

最后的最后给大家贴出今未3天的天气情况(北京地区)




  相关解决方案