Android之Http网络编程(四)

前面几篇博文简单的介绍了一些常见的Http的操作,这些操作几乎都是在新开的线程中进行的网络请求,并在日志中打印出获取到的网络数据。那么,问题来了!(呃~感觉下一句是蓝翔有木有?)如何在把获取到的网络数据显示在UI界面上呢?如果按照前几篇博文的例子,并在主线程中直接对子线程获取的网络数据直接进行操作就会发现一个问题,那就是在主线程中根本就获取不到子线程得到的从服务器返回的数据。因为,网络操作属于耗时操作,为了不阻塞主线程而放在子线程中,当主线程中的代码执行完后子线程未必就获取到服务器返回的数据了。所以,为了解决这样的问题我们通常在Http的操作中加上异步消息机制,并且为了简化操作对其进行简单的封装,加上回调机制。

 

这篇博文就以HttpClient访问百度首页为例子,对之前博文中的Http操作进一步的完善。

首先,先回忆一下使用HttpClient的最简单的步骤或者说是过程:

(这里的strurl为"http://www.baidu.com",str为从服务器返回的数据。)

HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(strurl);
HttpResponse response= client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String str = EntityUtils.toString(response.getEntity());
}

 

下面将基于上面的这些操作来实现简易封装:

首先加入回调机制:

(如果对回调还不太熟悉,请参考博文《java回调机制解析》)

public interface HttpCallback {void onSuccess(Object result);void onFailure(Exception result);}

 

 

接下来,实现一个Request类:

这个类一共有三个属性:

method是在该类中用enum类型限定的RequestMethod类型的对象,用于设置请求方式。

url就是网络请求的路径。

callback为回调接口对象,用于在网络请求中获取到数据后将数据传递至调用处。

public class Request {public RequestMethod method;public String url;public HttpCallback callback;public Request(String url, RequestMethod method) {this.method = method;this.url = url;}public Request(String url) {this.method = RequestMethod.GET;this.url = url;}public enum RequestMethod {GET, POST, DELETE, PUT}public void setCallBack(HttpCallback callback) {this.callback = callback;}public void execute() {RequstTask task = new RequstTask(this);task.execute();}}

从上面的代码可以看出,该类的两个构造函数,都需要传入URL,其中一个构造函数可以设置请求方式,另一个设置默认请求方式GET。
在该类中有一个execute()方法,在这个方法中RequestTask类继承于AsyncTask,它的作用就是在RequestTask中进行网络请求。

 

 

RequestTask代码如下:

public class RequstTask extends AsyncTask<Void, integer, Object> {private Request requset;public RequstTask(Request requset) {this.requset = requset;}@Overrideprotected void onPreExecute() {// TODO Auto-generated method stubsuper.onPreExecute();}@Overrideprotected Object doInBackground(Void... params) {try {HttpResponse response = HttpClientUtils.execute(requset);if (requset.callback != null) {//如果进一步抽象化回调接口,使其子抽象类能分别处理多种格式的数据(如:JSON、XML、String、File),可以更方便//这里直接使用返回String类型的数据if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){return EntityUtils.toString(response.getEntity());}return "请求失败";} else {return null;}} catch (Exception e) {return e;}}@Overrideprotected void onPostExecute(Object result) {if (requset.callback != null) {if (result instanceof Exception) {requset.callback.onFailure((Exception) result);} else {requset.callback.onSuccess(result);}}}@Overrideprotected void onProgressUpdate(integer... values) {// TODO Auto-generated method stubsuper.onProgressUpdate(values);}}

这个类的构造函数需要传递一个Request对象,会根据这个Request对象的method属性确定请求方式、url属性确定请求路径,根据callback属性的有无来判断是否是否将获取到的网络数据传递至调用接口处。
在doInBackground()中如果Request对象的callback属性为null则返回null:

当Request对象的callback属性不为null,则先取出服务器返回的状态码(这里的response为服务器返回的信息),如果等于200(也就是HttpStatus.SC_OK)那么就说明响应成功了。再调用getEntity()方法获取到一个HttpEntity实例,然后再用EntityUtils.toString()这个静态方法将HttpEntity转换成字符串并return。返回后的数据将传入onPostExecute()方法中作为参数。

      if (requset.callback != null) {//如果进一步抽象化回调接口,使其子抽象类能分别处理多种格式的数据(如:JSON、XML、String、File),可以更方便//这里直接使用返回String类型的数据if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){return EntityUtils.toString(response.getEntity());}return "请求失败";} else {return null;}

在onPostExecute()中Request对象的callback属性为null根本就没返回。反之,doInBackground()的结果result将会传递至回调接口的调用处:

    if (requset.callback != null) {if (result instanceof Exception) {requset.callback.onFailure((Exception) result);} else {requset.callback.onSuccess(result);}}

 

 

在doInBackground()中有一句代码:

HttpResponse response = HttpClientUtils.execute(requset);

这里的HttpClientUtils其实就是一个简单的封装,其代码如下:

public class HttpClientUtils {public static HttpResponse execute(Request requst) throws Exception {switch (requst.method) {case GET:return get(requst);}return null;}private static HttpResponse get(Request requst)throws ClientProtocolException, IOException {HttpClient client = new DefaultHttpClient();HttpGet get = new HttpGet(requst.url);HttpResponse response = client.execute(get);return response;}}

从代码中可以看出,execute()和get()方法都是static类型并且返回类型都是HttpResponse。在execute()方法中根据传入的Request对象的method属性结合switch语句执行相对应的网络请求方式,并返回从服务器获得HttpResponse类型的信息。这个信息在RequstTask类中被直接赋值使用。

 

 

大体的过程就是这样了。

最后的最后,在Activity中的使用:

public class MainActivity extends Activity {private Button btn;private TextView tv;private Request request;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);btn = (Button) findViewById(R.id.btn);tv = (TextView) findViewById(R.id.tv);request = new Request("http://www.baidu.com", RequestMethod.GET);btn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {try {request.setCallBack(new HttpCallback() {@Overridepublic void onSuccess(Object result) {tv.setText((String) result);}@Overridepublic void onFailure(Exception result) {tv.setText("请求失败");}});} catch (Exception e) {// TODO Auto-generated catch block
                    e.printStackTrace();}request.execute();}});}}

Activity的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><Buttonandroid:id="@+id/btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="请求" /><ScrollViewandroid:id="@+id/sv"android:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid:id="@+id/tv"android:layout_width="fill_parent"android:layout_height="fill_parent" /></ScrollView></LinearLayout>
View Code

 

 

运行程序,效果如下:

 

 

Demo下载:http://download.csdn.net/detail/af74776/8066779

转载于:https://www.cnblogs.com/scetopcsa/p/4021196.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/273551.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Java 高并发》02 多线程的特性

多线程的三大特性&#xff1a;原子性、可见性和有序性。 原子性 原子性是指一个操作或者多个操作&#xff0c;一旦开始就不会被其他线程干扰&#xff0c;即使是在多个线程一起执行的情况下也不会被干扰。或者不执行。 原子性主要是为了保证数据一致&#xff0c;线程安全问题…

U3D-FSM有限状态机的简单设计

http://coder.beitown.com/archives/592 在之前的文章里介绍了一个基础U3D状态机框架&#xff08;Unity3D游戏开发之状态流框架&#xff09;即大Switch的枚举状态控制。这种方法虽然容易理解&#xff0c;编程方法也相对简单&#xff0c;但是弊端是当状态变得复杂之后&#xff0…

《Java 高并发》04 线程的基本操作

新建线程 新建线程很简单。只要使用new 关键字创建一个线程对象&#xff0c;并且调用 start 方法启动线程。 Thread t new Thread(); t.start();注意&#xff1a;run 方法不是用来启动线程。如果调用 run 方法它只会作为普通方法来执行&#xff0c;而不会开启线程执行。 终止…

Dispatch 方法简介

后台执行 dispatch_async(dispatch_get_global_queue(0, 0), ^{ //后台程执行 something; }); 主线程执行 dispatch_async(dispatch_get_main_queue(), ^{// 主线程执行something; }); 一次性执行 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 主…

linux杂七杂八整理

64系统里执行32位程序&#xff1a; 1、在64系统里执行32位程序如果出现/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory&#xff0c;安装下glic即可sudo yum install glibc.i6862、error while loading shared libraries: libz.so.1: cannot …

《Java 高并发》05 线程的基本操作

volatile 与 Java 内存模型 Java 内存模型都是围绕着原子性、有序性和可见性展开的。为了在适当的场合&#xff0c;确保线程间的原子性、有序性和可见性。Java 使用了一些特许的操作或者关键字来申明、告诉虚拟机&#xff0c;在这个地方&#xff0c;要尤其注意&#xff0c;不能…

mybatis 2 -常用数据操作

1、写入数据并获取自增ID XML配置&#xff1a; <!-- 写入数据获取自增ID --><insert id"insertLog" parameterType"com.mamaguwen.entity.sys_loginlog" useGeneratedKeys"true" keyProperty"logid">insert into sys_…

Spring常用的的注解对应xml配置详解

Component(value"")注解&#xff1a;组件 标记在类上&#xff0c;也可以放在接口上注解作用&#xff1a;把AccountDao实现类对象交由Spring IOC容器管理 相当于XML配置文件中的Bean标签 <bean id"userAnnonMapper" class"com.spring.mapper.User…

安卓模拟器bluestacks mac地址修改教程

http://szmars2008.blog.163.com/blog/static/118893702201373181349348/ 转载于:https://www.cnblogs.com/prayer521/p/4069037.html

Docker 搭建 ELK 日志系统,并通过 Kibana 查看日志

Docker 搭建 ELK 日志系统,并通过 Kibana 查看日志 docker-compose.yml version: 3 services:elasticsearch:image: elasticsearch:7.7.0 #镜像container_name: elasticsearch #定义容器名称restart: always #开机启动&#xff0c;失败也会一直重启environment:- "cl…

蟠桃记

Problem Description 喜欢西游记的同学肯定都知道悟空偷吃蟠桃的故事&#xff0c;你们一定都觉得这猴子太闹腾了&#xff0c;其实你们是有所不知&#xff1a;悟空是在研究一个数学问题&#xff01; 什么问题&#xff1f;他研究的问题是蟠桃一共有多少个&#xff01; 不过&#…

Spring 定时任务动态管理

管理 Spring 中定时任务 pom.xml <properties><hutool.version>5.6.6</hutool.version><lombok.version>1.18.20</lombok.version><spring-boot.web.version>2.2.10.RELEASE</spring-boot.web.version> </properties><de…

高效率Oracle SQL语句

1、Where子句中的连接顺序&#xff1a; ORACLE采用自下而上的顺序解析WHERE子句。 根据这个原理&#xff0c;表之间的连接必须写在其他WHERE条件之前&#xff0c; 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。 举例&#xff1a; (低效) select ... from table1…

RabbitMQ Management:Management API returned status code 500

错误显示&#xff1a; 解决方案&#xff1a; 因为是使用docker 容器安装的&#xff0c;所有需要进入容器 docker exec -it rabbitmq /bin/bash进入目录 cd /etc/rabbitmq/conf.d/执行命令 echo management_agent.disable_metrics_collector false > management_agent.dis…

Android JNI和NDK学习(5)--JNI分析API

Java类型和本地类型对应 在如下情况下&#xff0c;需要在本地方法中应用java对象的引用&#xff0c;就会用到类型之间的转换&#xff1a; java方法里面将参数传入本地方法&#xff1b;在本地方法里面创建java对象&#xff1b;在本地方法里面return结果给java程序。Java基本类型…

RabbitMq 消费失败,重试机制

方案一&#xff1a; 本地消息表 定时任务 本地消息表&#xff1a;主要用于存储 业务数据、交换机、队列、路由、次数 定时任务&#xff1a;定时扫描本地消息表&#xff0c;重新给业务队列投递消息。 具体思路&#xff1a;业务队列消费失败时&#xff0c;把 业务数据、交换机、…

Android常用的工具类

主要介绍总结的Android开发中常用的工具类&#xff0c;大部分同样适用于Java。目前包括HttpUtils、DownloadManagerPro、ShellUtils、PackageUtils、 PreferencesUtils、JSONUtils、FileUtils、ResourceUtils、StringUtils、 ParcelUtils、RandomUtils、ArrayUtils、ImageUtils…

0. Spring 基础

BeanDefinition BeanDefinition 表示 Bean 定义&#xff1a; Spring根据BeanDefinition来创建Bean对象&#xff1b;BeanDefinition有很多的属性用来描述Bean&#xff1b;BeanDefiniton是Spring中非常核心的概念。BeanDefiniton中重要的属性&#xff1a; a. beanClass&#xf…

1. Spring 源码:Spring 解析XML 配置文件,获得 Bena 的定义信息

通过 Debug 运行 XmlBeanDefinitionReaderTests 类的 withFreshInputStream() 的方法&#xff0c;调试 Spring 解析 XML 配置文件&#xff0c;获得 Bean 的定义。 大体流程可根据序号查看&#xff0c;xml 配置文件随便看一眼&#xff0c;不用过多在意。 <?xml version&qu…

c++ 读取文件 最后一行读取了两次

用ifstream的eof()&#xff0c;竟然读到文件最后了&#xff0c;判断eof还为false。网上查找资料后&#xff0c;终于解决这个问题。 参照文件&#xff1a;http://tuhao.blogbus.com/logs/21306687.html 在使用C/C读文件的时候&#xff0c;一定都使用过eof&#xff08;&#xff0…