Android实现网络访问

开发工具:Andorid Studio 1.3

运行环境:Android 4.4 KitKat

工程内容

  1. 熟练使用HttpURLConnection访问WebService
  2. 熟练使用多线程以及Handler更新UI
  3. 熟练使用XmlPullParser解析xml文档数据

代码实现

当用户点击查询按钮的时候,用正则表达式匹配是否是手机号码,若是则调用查询函数,否则用Toast提示用户检查输入

((Button)this.findViewById(R.id.btnSearch)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (edtPhoneNumber.getText().toString().matches("^[1-9]\\d{10}$")) {
edtContent.setText("Querying the data");
sendRequestWithHttpURLConnection();
} else {
edtContent.setText("");
Toast.makeText(MainActivity.this, "Please correct the phone number", Toast.LENGTH_SHORT).show();
}
}
});

用户输入正确的时候,新开一个线程Thread在后台使用HttpURLConnection建立连接,设置请求方式是POST,设置连接超时和读数据超时为20s。如若超时捕获超时异常,更新UI显示为超时。然后往Http发送请求,给予手机号码,等待回复。接着从Http中读回返回的结果到一个String中。读回来的数据是Xml的字符串内容,需要用XmlPullParserFactory解析xml得到想要的内容。接着把这个得到的内容写入一个Message发出去让主线程的Handler捕获消息。良好习惯是,Http的connection要记得关闭,并且要让线程启动。

private void sendRequestWithHttpURLConnection() {
Thread workThread = new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
// Create a connection use url
//connection = (HttpURLConnection)((new URL(url.toString()).openConnection()));
connection = (HttpURLConnection)((new URL(getResources().getString(R.string.webService)).openConnection()));
Log.d("myDebug", "successfully open connection");
// Set method
connection.setRequestMethod("POST");
connection.setConnectTimeout(20000);
connection.setReadTimeout(20000);
Log.d("myDebug", "successfully set parameter");
// Write into outputStream
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
// use post method to post our data
out.writeBytes("mobileCode=" + edtPhoneNumber.getText().toString() + "&userID=");
Log.d("myDebug", "successfully write bytes");
// get response data
InputStream in = null;
if (connection.getResponseCode() == 200) {
in = connection.getInputStream();
} else {
in = connection.getErrorStream();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
Log.d("myDebug", "successfully get respone");
Message message = new Message();
message.what = UPDATE_CONTENT;
message.obj = parseXMLWithPull(response.toString());
handler.sendMessage(message);
Log.d("myDebug", "successfully send message");
} catch (java.net.SocketTimeoutException e) {
Message message = new Message();
message.what = TIME_OUT;
handler.sendMessage(message);
e.printStackTrace();
Log.d("myDebug", "Timeout to get the data");
} catch (Exception e) {
e.printStackTrace();
Log.d("myDebug", "Can't not connect to the service");
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
});
workThread.start();
} private String parseXMLWithPull(String xml) {
String str = "";
try {
// use pull to parse xml
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser(); parser.setInput(new StringReader(xml));
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
if ("string".equals(parser.getName())) {
str = parser.nextText();
}
break;
case XmlPullParser.END_TAG:
break;
default:
break;
}
eventType = parser.next();
}
} catch (Exception e) {
e.printStackTrace();
Log.d("myDebug", "can not parse the xml");
}
return str;
}

主线程中需要捕获消息并更新UI,只捕获自己的消息,其余消息交给父类原本的处理

private static final int UPDATE_CONTENT = 0;
private static final int TIME_OUT = 1;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case UPDATE_CONTENT:
edtContent.setText(message.obj.toString());
break;
case TIME_OUT:
edtContent.setText("Time out for getting the data");
break;
default:
super.handleMessage(message);
break;
}
}
};

最后需要给程序赋予上网权限和检测网络权限即可

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

效果图

初始化界面->输入错误或不完整手机号码->输入正确并查询->查询结果



一些总结

这个实验中最大的问题就在于免费的东西有使用次数限制,根据网站的说法是24小时内容不超过100次。

然后跟踪Http的进度使用Log方法来调试程序比较快。

对于有些超时的情况,我选择了捕获这个超时异常来更新UI,否则子线程超时后什么内容也没有显示不太符合正常情况。

实际上,在http请求中,直接使用主进程请求数据也是没问题的,为什么android非要使用子线程进行http请求呢?

答:Http请求并不能即时出结果,需要有时间等待,如果在主线程请求数据,那么请求的时候整个程序就会停留在请求的状态,界面卡住不动,因此使用子线程来做这件事比较合适。

为什么不在子线程中直接修改UI,而是需要通过Handler来实现消息的传递,如果直接修改UI会出现什么问题?

答:如果多个子线程同时修改一个UI,那个程序会出现未知的错误。因此每个子线程发送各自的消息,让主线程在消息队列中按到达顺序依次处理消息,是最好的办法。

工程下载

传送门:下载

Android实现网络访问的更多相关文章

  1. android的网络访问URL

    Thread visitBaiduThread = new Thread(new VisitWebRunnable());     visitBaiduThread.start();     try ...

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

    前言 啦啦啦各位小伙伴们好~ 一起进入我们今天的主题.今天我们将和大家学习网络访问和Web服务开发的相关知识,一起学习熟练使用 HttpURLConnection 访问 WebService,熟悉使用 ...

  3. android post 方式 访问网络 实例

    android post 方式 访问网络 实例 因为Android4.0之后对使用网络有特殊要求,已经无法再在主线程中访问网络了,必须使用多线程访问的模式 该实例需要在android配置文件中添加 网 ...

  4. Android下基于线程池的网络访问基础框架

    引言 现在的Android开发很多都使用Volley.OkHttp.Retrofit等框架,这些框架固然有优秀的地方(以后会写代码学习分享),但是我们今天介绍一种基于Java线程池的网络访问框架. 实 ...

  5. Android okHttp网络请求之Get/Post请求

    前言: 之前项目中一直使用的Xutils开源框架,从xutils 2.1.5版本使用到最近的xutils 3.0,使用起来也是蛮方便的,只不过最近想着完善一下app中使用的开源框架,由于Xutils里 ...

  6. Android okHttp网络请求之缓存控制Cache-Control

    前言: 前面的学习基本上已经可以完成开发需求了,但是在项目中有时会遇到对请求做个缓存,当没网络的时候优先加载本地缓存,基于这个需求我们来学习一直okHttp的Cache-Control. okHttp ...

  7. 使用Fiddler针对Android手机网络请求抓包

    本文转载自大牛Trinea的博文:Android利用Fiddler进行网络数据抓包 主要介绍Android及IPhone手机上如何利用Fiddler进行网络数据抓包,比如我们想抓某个应用(微博.微信. ...

  8. 网络--三种网络通讯方式及Android的网络通讯机制

    Android平台有三种网络接口可以使用,他们分别是:java.net.*(标准Java接口).Org.apache接口和Android.net.*(Android网络接口).下面分别介绍这些接口的功 ...

  9. 基于Retrofit+RxJava的Android分层网络请求框架

    目前已经有不少Android客户端在使用Retrofit+RxJava实现网络请求了,相比于xUtils,Volley等网络访问框架,其具有网络访问效率高(基于OkHttp).内存占用少.代码量小以及 ...

随机推荐

  1. linux程序调试常用命令

    1 调用跟踪 跟踪系统调用 strace ls –l 跟踪库调用  ltrace 2 lsof(list open file) 查看程序命令打开了哪些文件  lsof –p PID; lsof –c ...

  2. hosts文件导致打不开某些网站

    如果出现,某些网站访问不了,公司也没有进行限制的情况下,考虑是hosts文件出问题了. 解决办法:删除hosts文件,新建一个同名文件.

  3. IIS7 配置URL_REWRITE

    webconfig 文件 system.webServer节点下配置rewrite 报错 是因为需要安装URL重写 需要安装: https://www.microsoft.com/zh-cn/down ...

  4. javaSE第十天

    第十天    57 1. 形式参数和返回值的问题(理解)    57 (1)形式参数:    57 (2)返回值类型:    57 (3)链式编程    57 2. 包(理解)    57 (1)其实 ...

  5. CentOS学习笔记--时间

    时间 有装过Linux系统的人,可能都会有这样的经历,就是该机器安装windows系统时,时间正确,但是安装了linux系统后,尽管时区选择正确,也会发现系统时间不对.这是由于安装系统时采用了UTC, ...

  6. bootstrap中弹出窗体dialog的自定义

    感谢nakupanda的https://github.com/nakupanda/bootstrap3-dialog 根据需要弹出窗体,但是可以移动,不遮挡下面的内容,所以就修改了源代码,添加了一个属 ...

  7. Vue.js学习 Item5 -- 计算属性computed与$watch

    在模板中绑定表达式是非常便利的,但是它们实际上只用于简单的操作.模板是为了描述视图的结构.在模板中放入太多的逻辑会让模板过重且难以维护.这就是为什么 Vue.js 将绑定表达式限制为一个表达式.如果需 ...

  8. c# TextReader/TextWriter 的类

    TextReader以及TextWriter这两个类,非常有用,很多方法都接受它们作为参数. TextReader有两个子类: StringReader/StringWriter 用于读取字符串: S ...

  9. MongoDB 删除数据库

    MongoDB 删除数据库 语法 MongoDB 删除数据库的语法格式如下: db.dropDatabase() 删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名. 实例 以下 ...

  10. PHP empty函数报错的解决办法

    PHP empty函数在检测一个非变量情况下报错的解决办法. PHP开发时,当你使用empty检查一个函数返回的结果时会报错:Fatal error: Can't use function retur ...