在线请求天气API,并解析其中的json数据予以显示

Android网络与数据存储

第二章学习


在线请求天气API,并解析其中的json数据予以显示####

概要:

请求互联网信息提供商并取得返回的数据使用到HttpURLConnection,等待数据下载成功得到的Json,把它 解析成程序可利用的数据,使用到JSONObject


使用和风天气的API作为范例,只要注册就可免费用的还凑合的天气预报平台
http://www.heweather.com/

1.HttpURLConnection类的使用#####

本来Android发送Http请求拥有两种方式,分别是HttpURLConnection和HttpClient,但在Android 6.0时,HttpClient已经彻底从SDK里消失了,虽然是个重要的类,包括如今的阿里云服务中,也依然给我们提供了基于HttpClient的API请求SDK,由于版本问题,我也难以使用。(此处花费一整天用于折腾阿里云市场里购买的天气预报API,卒。)

所以,本着追赶潮流的思想,这次的App只使用HttpURLConnection进行网络请求。

0.生成HttpURLConnection对象:

API接口: https://api.heweather.com/x3/weather?cityid=城市ID&key=你的认证key

注册好以后,替换掉“城市ID”以及“你的认证key”字段即可使用

URL url = new URL("https://api.heweather.com/x3/weather?cityid=城市ID&key=你的认证key");
//将字符串转化为URL对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

1.给HttpURLConnection对象设置请求方式:
接下来给这个connection设置一种向网络服务器请求的方式,实际开发中我们用得较多的方式是Get和Post:

connection.setRequestMethod("GET");
  • Get:请求获取Request-URI所标识的资源
  • POST:在Request-URI所标识的资源后附加新的数据
  • HEAD 请求获取由Request-URI所标识的资源的响应信息报头
  • PUT:请求服务器存储一个资源,并用Request-URI作为其标识
  • DELETE:请求服务器删除Request-URI所标识的资源
  • TRACE:请求服务器回送收到的请求信息,主要用于测试或诊断
  • CONNECT:保留将来使用
  • OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项

说得太难懂,用GET和POST举个例子:

  • GET:在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔, 但数据容量通常不能超过2K,比如: “https://api.heweather.com/x3/weather?cityid=城市ID&key=你的认证key” 这种就是GET
  • POST: 这个则可以在请求的实体内容中向服务器发送数据,传输没有数量限制

2.定制HttpURLConnection并获取链接状态:

设置连接超过8000毫秒则为超时状态,同理还有读取超时

connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);

还可以获取当前连接的状态

int responseCode = connection.getResponseCode();

此时responseCode将会有非常多种数字有可能被返回,如“404”

  • 100~199 : 成功接受请求,客户端需提交下一次请求才能完成整个处理过程
  • 200: OK,客户端请求成功
  • 300~399:请求资源已移到新的地址(302,307,304)
  • 401:请求未授权,改状态代码需与WWW-Authenticate报头域一起使用
  • 403:Forbidden,服务器收到请求,但是拒绝提供服务
  • 404:Not Found,请求资源不存在,这个就不用说啦
  • 500:Internal Server Error,服务器发生不可预期的错误
  • 503:Server Unavailable,服务器当前不能处理客户端请求,一段时间后可能恢复正常

当然最好我们的返回代码是200,此时就成功了

3.获取输入流并转换为String类:

try {
    InputStream in = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
    StringBuilder response = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
            response.append(line).append("\r\n");
        }
    reader.close();
        } catch (Exception e) {
         e.printStackTrace();
     } finally {
     if (connection != null) {
     connection.disconnect();
     }
}

从网络请求的返回中获取输入流,并进行IO操作,结束后记得关掉BufferedReader和HttpURLConnection实例。此时,完成了一系列的操作后,我们取得了从网络返回的数据。

咳咳,插句题外话,当然也可以将返回数据解析为比特流返回

public class ToByteUtil {
    //从流中读取数据
    public static byte[] read(InputStream in) throws Exception{
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while((len = in.read(buffer)) != -1)
        //一行行读取,只要不为-1则表示没读完
        {
            out.write(buffer,0,len);
        }
        in.close();
        return out.toByteArray();
    }
}

以上成功获得了一个String,当前的API商提供给我们的是Json文件,Json文件并不会直接被系统识别,需要解析出其中的每一项,然后利用起来;

我们可以将对数据库进行的操作封装为一系列方法,如下:

4.看看Json的格式:

{"HeWeather data service 3.0":[{"basic":{"city":"大连","cnty":"中国","id":"CN101070201","lat":"38.944000","lon":"121.576000","update":{"loc":"2015-07-15 10:43","utc":"2015-07-15 02:46:14"}},"status":"ok","aqi":{"city":{"aqi":"71","co":"1","no2":"75","o3":"101","pm10":"89","pm25":"44","qlty":"良","so2":"27"}},"alarms":[{"level":"橙色","stat":"预警中","title":"辽宁省大连市气象台发布高温橙色预警","txt":"大连市气象台2015年07月14日13时31分发布高温橙色预警信号:预计14日下午至傍晚,旅顺口区局部最高气温将达到37℃以上,请注意防范。","type":"高温"}],"now":{"cond":{"code":"100","txt":"晴"},"fl":"33","hum":"28","pcpn":"0","pres":"1005","tmp":"32","vis":"10","wind":{"deg":"350","dir":"东北风","sc":"4-5","spd":"11"}},"daily_forecast":[{"date":"2015-07-15","astro":{"sr":"04:40","ss":"19:19"},"cond":{"code_d":"100","code_n":"101","txt_d":"晴","txt_n":"多云"},"hum":"48","pcpn":"0.0","pop":"0","pres":"1005","tmp":{"max":"33","min":"24"},"vis":"10","wind":{"deg":"192","dir":"东南风","sc":"4-5","spd":"11"}},{"date":"2015-07-16","astro":{"sr":"04:40","ss":"19:18"},"cond":{"code_d":"104","code_n":"104","txt_d":"阴","txt_n":"阴"},"hum":"82","pcpn":"2.7","pop":"82","pres":"1008","tmp":{"max":"27","min":"23"},"vis":"10","wind":{"deg":"116","dir":"东南风","sc":"4-5","spd":"11"}},{"date":"2015-07-17","astro":{"sr":"04:41","ss":"19:17"},"cond":{"code_d":"101","code_n":"100","txt_d":"多云","txt_n":"晴"},"hum":"70","pcpn":"0.1","pop":"11","pres":"1006","tmp":{"max":"28","min":"22"},"vis":"10","wind":{"deg":"172","dir":"西风","sc":"4-5","spd":"11"}}],"hourly_forecast":[{"date":"2015-07-15 10:00","hum":"51","pop":"0","pres":"1006","tmp":"32","wind":{"deg":"127","dir":"东南风","sc":"微风","spd":"4"}},{"date":"2015-07-15 13:00","hum":"49","pop":"0","pres":"1005","tmp":"34","wind":{"deg":"179","dir":"南风","sc":"微风","spd":"7"}},{"date":"2015-07-15 16:00","hum":"54","pop":"0","pres":"1005","tmp":"31","wind":{"deg":"216","dir":"西南风","sc":"微风","spd":"6"}},{"date":"2015-07-15 19:00","hum":"62","pop":"0","pres":"1005","tmp":"29","wind":{"deg":"192","dir":"西南风","sc":"微风","spd":"4"}},{"date":"2015-07-15 22:00","hum":"62","pop":"0","pres":"1006","tmp":"26","wind":{"deg":"154","dir":"东南风","sc":"微风","spd":"10"}}],"suggestion":{"comf":{"brf":"较舒适","txt":"白天天气晴好,您在这种天气条件下,会感觉早晚凉爽、舒适,午后偏热。"},"cw":{"brf":"较不宜","txt":"较不宜洗车,未来一天无雨,风力较大,如果执意擦洗汽车,要做好蒙上污垢的心理准备。"},"drsg":{"brf":"炎热","txt":"天气炎热,建议着短衫、短裙、短裤、薄型T恤衫等清凉夏季服装。"},"flu":{"brf":"少发","txt":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。"},"sport":{"brf":"较适宜","txt":"天气较好,但风力较大,推荐您进行室内运动,若在户外运动请注意防风。"},"trav":{"brf":"适宜","txt":"天气较好,是个好天气哦。稍热但是风大,能缓解炎热的感觉,适宜旅游,可不要错过机会呦!"},"uv":{"brf":"强","txt":"紫外线辐射强,建议涂擦SPF20左右、PA++的防晒护肤品。避免在10点至14点暴露于日光下。"}}}]}

妈呀密密麻麻的,我有密集恐惧症啊…………为了减少长度,我压缩了json文件,看不清,没关系,复制到http://www.runoob.com/jsontool 网页上就可以清楚看见文件的结构

{"now":{"cond":{"code":"100","txt":"晴"},"fl":"33","hum":"28","pcpn":"0","pres":"1005","tmp":"32","vis":"10","wind":{"deg":"350","dir":"东北风","sc":"4-5","spd":"11"}}}

json文件都是以键值对进行保存“键:值”,而如果值是个数组,则按如下表示

{Key:["status":"ok","city":"大连"]}

稍加观察,并不复杂

5.解析数据:

public class JsonUtil {
    public static ContentValues parseJSONToWeather(String jsonData) {
        ContentValues contentValues = new ContentValues();
        try {
            JSONObject jsonObject = new JSONObject(jsonData);
//此时将字符串转变为一个JSONObject实例,形象的说法就是{"key":"value"}这就是个object
            JSONArray jsonArray = jsonObject.getJSONArray("HeWeather data service 3.0");
//这里在此object中get了一个数组(JSONArray),输入这个数组的key,即可得到
            JSONObject allJsonObject = jsonArray.getJSONObject(0);
            String status = allJsonObject.getString("status");
            if (status.equals("ok")) {
                JSONObject basic = allJsonObject.getJSONObject("basic");
                contentValues.put("id", basic.getString("id"));
                contentValues.put("city", basic.getString("city"));
                JSONObject now = allJsonObject.getJSONObject("now");
                JSONObject now_cond = now.getJSONObject("cond");
                contentValues.put("now_cond_txt", now_cond.getString("txt"));
                contentValues.put("now_tmp", now.getString("tmp"));
                JSONArray daily_forecast = allJsonObject.getJSONArray("daily_forecast");
                for (int i = 0; i < 5; i++) {
                    String num = null;
                    switch (i){
                        case 0:
                            num = "first";
                            break;
                        case 1:
                            num = "second";
                            break;
                        case 2:
                            num = "third";
                            break;
                        case 3:
                            num = "fourth";
                            break;
                        case 4:
                            num = "fifth";
                            break;
                    }
                    JSONObject data = daily_forecast.getJSONObject(i);
                    contentValues.put(num + "_date", data.getString("date"));
                    JSONObject cond = data.getJSONObject("cond");
                    contentValues.put(num + "_txt_d", cond.getString("txt_d"));
                    contentValues.put(num + "_txt_n", cond.getString("txt_n"));
                    JSONObject tmp = data.getJSONObject("tmp");
                    contentValues.put(num + "_tmp_max", tmp.getString("max"));
                    contentValues.put(num + "_tmp_min", tmp.getString("min"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return contentValues;     //包含了所有的数据库信息
    }
}

代码解析:

基本上就Object和Array这两种东西,慢慢按照结构把最终的值使用类似getString的方法取到。慢慢扣出了我需要提取的数据……

最后我将取得的键值组成了ContentValues,,其实本来用Map类型进行保存的,然后在外部在再次转换为ContentValues进行数据库操作,后来转念一想这两东西结构不是一样的嘛!!!于是省了一步……

因为json里的数据名有重名的,我稍微利用for循环和switch进行重命名,数据库不接受数字开头的字符串当列名……

将数据缓存到数据库,而页面显示时,直接从数据库提取数据,最终效果就是这样了

-完-

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式。”但是在要求详细讲述它所提出的各个约束,以及如...
    时待吾阅读 3,417评论 0 19
  • API定义规范 本规范设计基于如下使用场景: 请求频率不是非常高:如果产品的使用周期内请求频率非常高,建议使用双通...
    有涯逐无涯阅读 2,521评论 0 6
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,825评论 25 707
  • 2017.01.09 今天的反省先说一个感受啊,就是通过最近这两次的训练觉得王教练简直太重要了!太重要了!太重要了...
    伪王小豆阅读 295评论 0 0