Android开发9:网络访问&Web服务开发

前言

  啦啦啦各位小伙伴们好~

  一起进入我们今天的主题。今天我们将和大家学习网络访问和Web服务开发的相关知识,一起学习熟练使用 HttpURLConnection 访问 WebService,熟悉使用多线程以及 Handler 更新 UI,熟悉使用 XmlPullParser 解析 xml 文档数据,了解 RecyclerView 控件的使用。

 

基础知识

一、网络访问&Web服务开发

 1 、实验WebService 地址

  (1)实验中所使用的 WebService 地址为:http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?op=getWeather

  在浏览器打开实验需要的 WebService 网站可以看到截图如下:

    可以看到,查询需要用到两个参数 theCityCode(默认参数为上海)和 theUserID,如果使用免费的 WebService,其中 theUserID 置空即可,输入后点击调用,查看返回值:

可以看到其中返回的数据为 xml 文件格式,我们需要用 XmlPullParser 提取我们需要的信息。

(2)有兴趣可以在网站上看一下如何免费使用 WebService:http://www.webxml.com.cn/zh_cn/web_services.aspx

PS:免费用户 24 小时内查询不超过 50 次并且获取二次数据大于间隔 600ms
(如果测试时超过上限更换一下网络 IP 重新测试即可)

 

2 、网络访问

在本次实验中使用 HttpURLConnection 实现网络访问:

(1) 在 manifest 中添加网络访问权限:

    (2) 判断是否有可用网络:使用 ConnectivityManager 获取手机所有连接管理对象,使用 manager 获取 NetworkInfo 对象,最后判断当前网络状态是否为连接状态即可。

(3) 定义我们需要用到的 WebService 地址:

(4) 使用 HttpURLConnection 新建一个 http 连接,新建一个 URL 对象,打开连接即可,并且设置访问方法以及时间设置:

    (5)将我们需要请求的字段以流的形式写入 connection 之中,这一步相当于将需要的参数提交到网络连接,并且请求网络数据(类似于 html 中的表单操作,将 post 数据提交到服务器)

(6)网页获取 xml 转化为字符串:

  在 logcat 中查看一下 response,实际上就是将网站上的 xml 转化为 string 而已,便于下一步的 xml 数据解析

(7)关闭 connection:

    (8)注:Android4.0 之后,http 请求需要开启子线程,然后由子线程执行请求,所以我们之前所写代码都是在子线程中完成的,并且使用 XmlPullParser 进行解析从而得到我们想要的数据:

 

3 、Handler 更新 UI

在之前的实验中我们已经知道,子线程中不能直接修改 UI 界面,需要中间人 handler 进行UI 界面的修改:

Message 消息机制:负责在不同的线程之间进行交互处理,我们先定义消息类型:

然后将我们需要的内容通过消息传递回来:

 

4 、XmlPullParser 解析 xml 文档

首先获取 XmlPullParser 对象实例,然后设置需要解析的字符串,最后按照 tag 逐个获取所需要的 string:

注:

  由于我们获取的 xml 字符串是 string 类型的数组(ArrayofString),所以我们也可以将按照 string(Tag)获取的字符串储存到ArrayList<String>中,然后在 Handler 中再进行处理,不断的将所需要的字符串进行分割处理,以用来更新 UI 界面。

异常处理部分:

1)城市名输入错误时:注意判断取回的字符串是否是“查询结果为空。…”

2)二次查询间隔<600ms 时:注意判断取回的字符串是否是“发现错误:免费用户不能使用高速访问。…”

3)达到上限 50 次:注意判断取回的字符串是否是“发现错误:免费用户 24 小时内访问超过规定数量。…”

 

二 、RecyclerView 控件使用

  RecyclerView 是 support-v7 包中的新组件,是一个强大的滑动组件,与经典的 ListView相比,同样拥有 item 回收复用的功能。RecyclerView 是 ListView 的升级版,最为突出的就是其拓展性极强,并且灵活性高。

(1)导入 RecyclerView 的 jar包,导入方法:

  http://jingyan.baidu.com/article/e6c8503c7190b7e54f1a1893.html

(2) RecylerView 的设置

(3)Adapter 的构造:

package com.example.administrator.ex9;
import java.util.ArrayList;
import java.util.List;
import android.R.integer;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
public class WeatherAdapter  extends RecyclerView.Adapter<WeatherAdapter.ViewHolder>{
private ArrayList<Weather>  weather_list;
private LayoutInflater  mInflater;
public interface OnItemClickLitener
{
void onItemClick(View view,  int position,Weather item);
}
private OnItemClickLitener  mOnItemClickLitener;
public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
{
this. mOnItemClickLitener = mOnItemClickLitener;
}
public WeatherAdapter(Context context,ArrayList<Weather> items) {
super();
weather_list = items;
mInflater = LayoutInflater.from(context);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup,  int i) {
View view =  mInflater.inflate(R.layout. weather_item, viewGroup,  false);
ViewHolder holder =  new ViewHolder(view);
holder. Date = (TextView)view.findViewById(R.id. date);
holder. Weather_description =(TextView)view.findViewById(R.id. weather_description);
holder. Temperature = (TextView)view.findViewById(R.id. temperature);
return holder;
}
@Override
public void onBindViewHolder( final ViewHolder viewHolder, final int i) {
viewHolder. Date.setText( weather_list.get(i).getDate());
viewHolder. Weather_description.setText( weather_list.get(i).getWeather_description());
viewHolder. Temperature.setText( weather_list.get(i).getTemperature());
if ( mOnItemClickLitener !=  null)
{
viewHolder. itemView.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
//  TODO  Auto- - generated method stub
mOnItemClickLitener.onItemClick(viewHolder. itemView, i, weather_list.get(i));
}
});
}
}
@Override
public int getItemCount() {
return  weather_list.size();
}
public static class ViewHolder  extends RecyclerView.ViewHolder{
public ViewHolder(View itemView) {
super(itemView);
}
TextView  Date;
TextView  Weather_description;
TextView  Temperature;
}
}

(3) Handler 中得到 weather_list 之后,绑定 adpter:

 

实验内容

实现一个简单的天气查询应用,具体要求如下:

1)该界面为应用启动之后的主界面                            2)点击 Search 按钮后(若网络不可用)

                                   

 

3)输入城市名 Search(网络可用且城市名正确)      4)输入城市名 Search(城市名不正确)

                                      

 

 5)快速点击按钮(二次查询<600ms)                               6)查询达到上限 50 次

                                  

 

实验过程

  本次实验主要是实现一个简单的天气查询应用,实现天气查询的功能。本次实验主要涉及使用 HttpURLConnection 访问 WebService,使用多线程以及Handler 更新 UI,熟悉使用 XmlPullParser 解析 xml 文档数据,了解RecyclerView 控件的使用。首先,写好界面的 XML 布局文件。这里我们需要设置一个 EditText 和一个搜索 Button,并在一个以@drawable/shape 为背景的 LinearLayout 中嵌套几个LinearLayout 以显示不同的数据,再往下设置一个 ListView 显示天气的详细内容,最后设置一个RecyclerView来显示接下来五天的天气概况。listview的item界面布局中设置两个 TextView,RecyclerView 的 item 界面布局中设置三个TextView。背景 shape 如下:

  接下来完成 MainActivity.java 类,在类中我们将使用 HttpURLConnection实现网络访问。在初始化控件后,在 manifest 中添加网络访问权限:

  定义我们需要用到的 WebService 地址:

  然后判断是否有可用网络。这里使用 ConnectivityManager 获取手机所有连接管理对象,使用 manager 获取 NetworkInfo 对象,最后判断当前网络状态是否为连接状态(写到 search 按钮事件中):

在按钮事件中,我们还需要利用设置好的时间参数,用判断语句判断两次查询间隔是否小于 600ms 以及查询栏输入是否为空:

http 请求需要开启子线程 ,然 后由 子 线程执 行请 求, 并且使用XmlPullParser 进行解析从而得到我们想要的数据:

在子线程中,使用 HttpURLConnection 新建一个 http 连接,新建一个 URL对象,打开连接即可,并且设置访问方法以及时间设置:

将我们需要请求的字段以流的形式写入 connection 之中,这一步相当于将需要的参数提交到网络连接,并且请求网络数据:

网页获取 xml 转化为字符串:

在子线程中使用 Message 消息机制,以实现在不同的线程之间进行交互处理。在定义消息类型后,将我们需要的内容通过消息传递回来:

然后关闭 connection:

  在子线程执行完请求之后,XmlPullParser 解析 xml 文档,首先获取XmlPullParser 对象实例,然后设置需要解析的字符串,最后按照 tag 逐个获取所需要的 string:

然后使用Handler 进行更新,子线程中不能直接修改 UI 界面,需要 handler进行 UI 界面的修改:

更新 Toast 的产生:

    更新城市名和更新时间信息(由于我们获取的 xml 字符串是 string 类型的数组(ArrayofString),所以我们也可以将按照 string(Tag)获取的字符串储存到 ArrayList<String>中,然后在 Handler 中再进行处理):

  在取有背景色的文本框所包含的数据时 , 我们需要 Java 中的StringTokenizer 类不断的将所需要的字符串进行分割处理,以用来更新 UI 界面。

  StringTokenizer 是字符串分隔解析类型,属于:Java.util 包。在 StringTokenizer 中,所有方法均为 public,书写格式为:[修饰符] <返回类型><方法名([参数列表])>——

int countTokens():返回 nextToken 方法被调用的次数。
boolean hasMoreTokens():返回是否还有分隔符。
boolean hasMoreElements():返回是否还有分隔符。
String nextToken():返回从当前位置到下一个分隔符的字符串。
Object nextElement():返回从当前位置到下一个分隔符的字符串。
String nextToken(String delim):与 4 类似,以指定的分隔符返回结果。


则可以分割其中的数据来更新 UI 界面:

在更新 ListView 中的信息时,我们还是需要使用键值对来保存数据:

 

  接下来完成拓展内容 RecyclerView 控件使用。

  RecyclerView 是 support-v7 包中的新组件,是一个强大的滑动组件,与经典的 ListView 相比,同样拥有 item 回收复用的功能。RecyclerView 是ListView 的升级版,最为突出的就是其拓展性极强,并且灵活性高。在导入 RecyclerView 的 jar 包后,对 RecylerView 进行设置:

按照文档中的要求设置好适配器 WeatherAdapter,并在 Weather 类中存储相应的数据:

更新 recyclerView 中的信息时,按照 string(Tag)获取字符串:

并且设置三个字符串组将五天的天气信息添加到其中:

按照顺序将五天的信息添加进 weather_list 中去:

Handler 中得到 weather_list 之后,绑定 adpter:

完成实验~

 

实验截图

 

其他总结

WebService:

  WebService 是发布在网络上的 API,可以通过发送 XML 调用,WebService返回结果也是 XML 数据。

Android 开发过程中为什么要多线程:

我们创建的 Service、Activity 以及 Broadcast 均是一个主线程处理,这里我们可以理解为 UI 线程。但是在操作一些耗时操作时,比如 I/O 读写的大文件读写,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现 ANR的响应提示窗口,这个时候我们可以考虑使用 Thread 线程来解决。

实验中我们还使用多线程以及 Handler 更新 UI。
使用 Handler 更新 UI 的原因:

  (1)如果当前线程和主线程不相等的话,更新 UI 就会抛出异常;
  (2)Activity 检查当前线程和主线程是否相等是在 onResume()方法才
开始的;
  (3)所以在新开启的线程,如果不休眠直接更新 UI 的话不会抛出异常;
  (4)如果休眠再做更新 UI 操作的话就会抛出异常。

 

源码下载

  源码下载点击这里~

 

1、本实验实验环境:

操作系统 Windows 10 

实验软件 Android Studio 2.2.1

虚拟设备:Nexus_5X

API:23

2、贴代码的时候由于插入代码框的大小问题,代码格式不太严整,望见谅~

 

posted @ 2017-02-23 22:51  yanglh6  阅读(1666)  评论(1编辑  收藏  举报