Android网络与数据存储——网络编程数据处理(网络请求,解析xml,解析Json)

手机的优势是携带方便,可以随时打开,而且手机通常总是处于联网状态的,所以网络支持对于手机很重要。而且Java的网络编程完全适用于Android网络编程。

一.网络请求


1.URL

在真正学习网络请求之前有必要了解一下什么是URL,URL的英文全拼是Uniform Resource Locator,翻译过来为统一资源定位器,大概意思就是URL是指向互联网资源的指针。

这里说的资源可以是文件或目录,也可以是对象的引用,例如对数据库或搜索引擎的查询。

URL的组成:协议名、主机、端口和资源。即满足如下格式:

protocol://host:port/resourceName

例如 google的URL地址:

https://www.google.com

URL类提供了多个构造器用于创建URL对象,一旦获得了URL对象之后,就可以访问该URL对象对应的资源了。

2.Http网络请求

Android中的Http网络请求有两种方式:

  • HttpURLConnection
  • HttpClient(已不推荐使用)

既然HttpClient已被弃用,那就用HttpURLConnection。

HttpURLConnection继承了URLConnection,可用于向指定网站发送GET请求、POST请求。提供了一下方法:

  • HttpURLConnection openConnection():返回一个HttpURLConnection对象,表示到URL所引用的远程对象的连接。
  • int getResponseCode():获取服务器的响应代码。例如:200表示服务器成功响应,404表示没响应。
  • String getResponseMessage():获取服务器的响应消息。
  • String getRequestMethod():获取发送请求的方法。
  • void setRequestMethod():设置发送请求的方法。
  • void setConnectTimeout():设置连接超时时间。
  • void setReadTimeout():设置读取超时时间。

下边写一个请求百度API获取全国城市的方法来使用上面提到的方法。代码如下:

public void requestCityData(final String urlString) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(urlString);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.connect();
                    if (connection.getResponseCode() == 200) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                        String line;
                        StringBuilder builder = new StringBuilder();
                        while ((line = reader.readLine()) != null) {
                            builder.append(line);
                        }
                        reader.close();
                        String result = builder.toString();
                        Message msg = new Message();
                        msg.what = 0;
                        msg.obj = result;
                        handler.sendMessage(msg);
                    }
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
}

从以上代码可以看出请求网络数据的方法可以分为以下步骤:

  • 创建URL对象url。
  • 通过url.openConnection()获取HttpURLConnection对象connection。
  • 设置请求方式、连接延迟、读取延迟、连接。
  • 通过connection.getResponseCode()获取响应码来判断是否连接成功。
  • 如果连接成功,接下来的读取文件和Java的读文件操作一样。
  • 由于请求网络数据的操作属于耗时操作,所以应该把整个请求操作放在了子线程(处理异步数据有两种方式:handler和AsyncTask,这里用handler进行实现,下一篇中的利用多线程下载会用AsyncTask),最后把请求到的数据通过handler.sendMessage()方法发送到主线程,在handler中的handleMessage()方法中对请求到的数据进行处理。handler代码如下:
Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    String cityData = msg.obj.toString();
                    Log.d("CityActivity", cityData);
                    break;
            }
        }
};

这里的handler只是简单的打印了一下请求到的数据。

到目前为止,还不算请求完成,因为这里用到了网络,要想获取网络上的数据,该应用必须有请求网络的权限,在AndroidManifest.xml中加入网络权限即可。

<uses-permission android:name="android.permission.INTERNET" />

二.解析xml


如果请求到的数据为xml类型的,就需要把xml类型的数据解析成我们想要的类型或从xml类型的数据中解析出我们想要的数据。

解析xml类型数据有两种方式:

  • SAX:基于事件驱动的解析(解析器+事件处理器),较复杂。
  • PULL
  • DOM:基于文件流。

SAX、PULL是一个标签一个标签读,分段加载;DOM是整个文件读取出来,然后加载。

1.SAX

利用SAX解析如下xml中的id、url以及item text。

<?xml version="1.0" encoding="utf-8"?>
<web>
    <item id = "0" url = "http://www.baidu.com" >百度</item>
    <item id = "1" url = "http://www.sogou.com" >搜狗</item>
    <item id = "2" url = "http://www.sohu.com" >搜狐</item>
</web>

先新建一个SAXParseHandler类继承自DefaultHandler,并实现startDocument()、startElement()、characters()、endElement()、endDocument()这五个方法。

public class SAXParseHandler extends DefaultHandler {

    private List<WebURL> mWebURLs;
    private WebURL mWebURL;
    private boolean state = false;

    @Override
    public void startDocument() throws SAXException {
        mWebURLs = new ArrayList<>();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        mWebURL = new WebURL();
        if (TextUtils.equals(localName, "item")){
            for (int i = 0; i < attributes.getLength(); i++) {
                if (TextUtils.equals(attributes.getLocalName(i), "id")){
                    mWebURL.setmID(Integer.parseInt(attributes.getValue(i)));
                }else if (TextUtils.equals(attributes.getLocalName(i), "url")){
                    mWebURL.setmUrl(attributes.getValue(i));
                }
            }
            state = true;
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String content = String.valueOf(ch, start, length);
        if (state) {
            mWebURL.setmContent(content);
            state = false;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (TextUtils.equals(localName, "item")){
            mWebURLs.add(mWebURL);
        }
    }

    @Override
    public void endDocument() throws SAXException {
    }
}

以上代码中startDocument()表示解析到最外层的标签,进行一些初始化操作,startElement()表示解析到子标签,通过attributes来获取该标签的属性id和url,characters()表示子标签开始标签和结束标签中间的内容,在这里通过转换ch可以获取到,endElement()表示结束子标签,在这个方法中将获取到的信息进行保存,endDocument()表示解析结束。

SAXParseHandler类将xml的每一个标签进行了遍历,接下来就是通过SAX解析器进行解析了。解析代码如下:

private void testSAXParse() throws ParserConfigurationException, SAXException, IOException {
        //定义一个factory API,能够配置和获取一个SAX解析器去解析xml
        //SAXParserFactory.newInstance();返回Android的接口SAXParserFactory,不像其他Java接口,该方法不能产生系统属性
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();//属性文件或服务API
        //定义一个API包裹XMLReader实现类
        SAXParser saxParser = saxParserFactory.newSAXParser();
        //读一个xml文档的接口,用于回调
        XMLReader xmlReader = saxParser.getXMLReader();
        saxParseHandler = new SAXParseHandler();
        //将saxParseHandler的实例设置到XMLReader中
        xmlReader.setContentHandler(saxParseHandler);
        InputStream inputStream = getResources().openRawResource(R.raw.test);
        InputSource inputSource = new InputSource(inputStream);
        //开始执行解析
        xmlReader.parse(inputSource);
    }

以上代码中的注释写的很详细,就不在啰嗦了。

2.PULL

待补充...

三.解析Json


Android中解析Json的类有JSONObject和JSONArray。

格式化Json数据的网址:jsonlint.com

开源库:对开源库还未进行研究,待研究了回来补充...

  • GSON
  • fastJson

通过JSONObject和JSONArray来对下面一段Json数据进行解析。

{city_info: [ 
{city: "南子岛", cnty: "中国", id: "CN101310230", lat: "11.26", lon: "114.20", prov: "海南" }, 
{city: "北京", cnty: "中国", id: "CN101010100", lat: "39.904000", lon: "116.391000", prov: "直辖市" }, ... 
] }

写一个方法对以上Json数据进行解析,代码如下:

public List<CityInfo> parseCityData(String cityData) {
        List<CityInfo> cityInfos = new ArrayList<>();
        try {
            JSONObject jsonObject = new JSONObject(cityData);
            JSONArray jsonArray = jsonObject.getJSONArray("city_info");

            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject cityObject = (JSONObject) jsonArray.get(i);
                String city = cityObject.getString("city");
                String prov = cityObject.getString("prov");
                CityInfo cityInfo = new CityInfo(city, prov);
                cityInfos.add(cityInfo);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return cityInfos;
}

通过new JSONObject()获取整个JSONObject对象,然后利用getJSONArray()获取city_info对应的Json数组,然后再通过Json数组的get方法获取数组中的每一个JSONObject对象,通过关键字获取我们想要的数据,最后将数据存入列表。整个Json数据解析完毕。

四.网络状态处理


网络状态处理:可以判断是否连接网络,还可以区分移动网络流量还是WiFi网络流量

  • ConnectivityManager
  • NetworkInfo

五.扩展


  1. 下载电影、音乐的本质?
    网络请求
  2. 断点下载
    记录http的Head,下载时间,下载了哪些东西。
  3. 常用网络开源库
  • android-async-http
  • volley
  • OKHttp
  • Retrofit
  1. 封装请求及通用设置
  • 封装能用Header
  • 请求参数封装
  1. 封装结果处理
  • 能用错误码处理
  • 数据转换校验
  1. 拦截请求设置及代理
  • Fiddler(Windows)
  • Charles(Mac)
  • wifi设置代理
  1. 技巧
  • Postman查询API
  • Restful API
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 1 XML解析No29 【 XML:可拓展标记语言,语言和HTML类似,也是一种标记语言。 特点:标记是自定义...
    征程_Journey阅读 1,624评论 0 9
  • JSON JSON和XML都是需要解析的 JSON是一种轻量级的数据格式,一般用于数据交互服务器返回给客户端的数据...
    JonesCxy阅读 1,838评论 2 10
  • 从小是个无肉不欢的我特别喜欢的就是过年,因为每逢过年的时候家里就会烧一桌子好吃的,当然必少不了我最爱吃的红烧肉。 ...
    3f17274cd933阅读 372评论 0 0
  • 多希望有一天突然惊醒,发现自己在高中的一节课上睡着了,现在经历的一切都是一场梦,桌上满是你的口水。你告诉同桌...
    风雪依然阅读 309评论 0 1