`
zhouxiaoli521
  • 浏览: 566357 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android 实现联网(三) 在线程中联网

阅读更多

在前面的关于Java I/O的学习中,有一个我们需要牢记的是:对数据流的操作都是阻塞的,在一般情况下,我们是不需要考虑这个问题的,但是在Android 实现联网的时候,我们必须考虑到这个问题。比如:从网络上下载一张图片:
public Bitmap returnBitmap(String url)
{
URL myFileUrl = null;
Bitmap bitmap = null;
try{
myFileUrl = new URL(url);
}catch(MalformedURLException e){
e.printStackTrace();
return null;
};
try{
HttpURLConnection conn = (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bitmap = BitmapFactroy.decodeStream(is);
is.close();
}catch(IOException e){
e.printStackTrace();
}
return bitmap;
}
由于网络连接需要很长的时间,需要3-5秒,甚至更长的时间才能返回页面的内容。如果此连接动作直接在主线程,也就是UI线程中处理,会发生什么情况呢?整个程序处于等待状态,界面似乎是“死”掉了。为了解决这个问题,必须把这个任务放置到单独线程中运行,避免阻塞UI线程,这样就不会对主线程有任何影响。举个例子如下:
private void connect(String strURL){
new Thread() {
public void run() {
try {
HttpClient client = new DefaultHttpClient();
// params[0]代表连接的url
HttpGet get = new HttpGet(url.getText().toString());
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
long length = entity.getContentLength();
InputStream is = entity.getContent();
String s = null;
if (is != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int ch = -1;
int count = 0;
while ((ch = is.read(buf)) != -1) {
baos.write(buf, 0, ch);
count += ch;
}
s = new String(baos.toByteArray());
Log.V(“moandroid sample”,s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}

使用Handler更新界面

如何将下载的信息显示在界面上了,比如说下载的进度。Android SDK平台只允许在主线程中调用相关View的方法来更新界面。如果返回结果在新线程中获得,那么必须借助Handler来更新界面。为此,在界面Activity中创建一个Handler对象,并在handleMessage()中更新UI。
//Task在另外的线程执行,不能直接在Task中更新UI,因此创建了Handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String m = (String) msg.obj;
message.setText(m);
}
};
只需要将上面的
Log.V(“moandroid sample”,s);
替换为:
s = new String(baos.toByteArray());
Message mg = Message.obtain();
mg.obj = s;
handler.sendMessage(mg);

AsyncTask

看上去修改后的connect()方法已经可用了,但是这种匿名程的方式是存在缺陷的:

  • 线程的开销较大,如果每个任务都要创建一个线程,那么应用程 序的效率要低很多;
  • 线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负。
  • 另外,前面已经看到,在新线程中更新UI还必须要引入handler,这让代码看上去非常臃肿。

为了解决这一问题,Android在1.5版本引入了AsyncTask。AsyncTask的特点是任务在主线程之外运行,而回调方法是在主线程中执行,这就有效地避免了使用Handler带来的麻烦。阅读AsyncTask的源码可知,AsyncTask是使用java.util.concurrent 框架来管理线程以及任务的执行的,concurrent框架是一个非常成熟,高效的框架,经过了严格的测试。这说明AsyncTask的设计很好的解决了匿名线程存在的问题。
AsyncTask是抽象类,其结构图如下图所示:
AsyncTask-class
AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。

子类必须实现抽象方法doInBackground(Params… p) ,在此方法中实现任务的执行工作,比如连接网络获取数据等。通常还应该实现onPostExecute(Result r)方法,因为应用程序关心的结果在此方法中返回。需要注意的是AsyncTask一定要在主线程中创建实例。
AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,需要注意的是这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。在任务的执行过程中,这些方法被自动调用,运行过程,如下图所示:

AsyncTask-Usage

  • onPreExecute() 当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • doInBackground(Params…) 此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
  • onProgressUpdate(Progress…) 此方法在主线程执行,用于显示任务执行的进度。
  • onPostExecute(Result) 此方法在主线程执行,任务执行的结果作为此方法的参数返回。

举个简单的例子如下:
// 设置三种类型参数分别为String,Integer,String
class PageTask extends AsyncTask {
// 可变长的输入参数,与AsyncTask.exucute()对应
@Override
protected String doInBackground(String… params) {
try {
HttpClient client = new DefaultHttpClient();
// params[0]代表连接的url
HttpGet get = new HttpGet(params[0]);
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
long length = entity.getContentLength();
InputStream is = entity.getContent();
String s = null;
if (is != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int ch = -1;
int count = 0;
while ((ch = is.read(buf)) != -1) {
baos.write(buf, 0, ch);
count += ch;
if (length > 0) {
// 如果知道响应的长度,调用publishProgress()更新进度
publishProgress((int) ((count / (float) length) * 100));
}
// 为了在模拟器中清楚地看到进度,让线程休眠100ms
Thread.sleep(100);
}
s = new String(baos.toByteArray()); }
// 返回结果
return s;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected void onPostExecute(String result) {
// 返回HTML页面的内容
message.setText(result);
}
@Override
protected void onPreExecute() {
// 任务启动,可以在这里显示一个对话框,这里简单处理
message.setText(R.string.task_started);
}
@Override
protected void onProgressUpdate(Integer… values) {
// 更新进度
message.setText(values[0]);
}
}
执行PageTask非常简单,只需要调用如下代码。
PageTask task = new PageTask();
task.execute(url.getText().toString());

总结说明

Handler在前面我们已经学习过,今天突然看到AsyncTask,以及学习其他人的博客基础上,做出了上面的总结,感觉自己收获很多,在这里与大家分享。

分享到:
评论

相关推荐

    cole_02_0507.pdf

    cole_02_0507

    工程硕士开题报告:无线传感器网络路由技术及能量优化LEACH协议研究

    内容概要:南京邮电大学工程硕士研究的无线传感器网络路由技术。通过对无线传感器网络路由协议的历史和研究现状进行了详细探讨,着重介绍了SPIN、LEACH、TEEN、pEGASIS等常见协议的特点、优势与局限性。文中分析了现有路由协议中的能量管理和网络覆盖问题,并提出了一种结合最大覆盖模型的改进型能量LEACH协议来应对这些问题。该研究旨在提高无线传感网络能量效率和覆盖效果,从而拓展其在各行业尤其是环境监测和军事安全领域的大规模应用。 适合人群:本篇文章主要面向具有无线传感网路研究背景或对此有兴趣的研究人员、工程师和技术爱好者,特别是在能源消耗控制上有较高需求的应用开发者。 使用场景及目标:①帮助理解和选择合适的无线传感器网络路由技术;②指导开发新路由协议时关注的关键要素;③为企业实施物联网相关项目提供理论支撑。 其他说明:文章强调了优化算法对于改善系统性能的重要性,并展示了具体的实施方案。通过仿真实验对不同协议的效果进行了验证,体现了科学研究的严谨态度与实践导向。

    【东海期货-2025研报】东海贵金属周度策略:金价高位回落,阶段性回调趋势初现.pdf

    【东海期货-2025研报】东海贵金属周度策略:金价高位回落,阶段性回调趋势初现.pdf

    图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作)

    【资源介绍】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,也可以作为小白实战演练和初期项目立项演示的重要参考借鉴资料。 3、本资源作为“学习资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研和多多调试实践。 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip 图像数据处理工具+数据(帮助用户快速划分数据集并增强图像数据集。通过自动化数据处理流程,简化了深度学习项目的数据准备工作).zip

    diminico_02_0709.pdf

    diminico_02_0709

    agenda_3cd_01_0716.pdf

    agenda_3cd_01_0716

    A课件Python全栈开发线下班.zip

    目录: 第1章 Linux命令入门及VIM编辑器 第2章Python基础 第3章Python面向对象编程 第4章数据结构与算法 第5章UDP与TCP通信 第6章多进程编程 第7章多线程编程 第8章协程 第9章正则表达式 第10章 Http协议 Web服务器并发服务器 第11章网络通信过程 第12章 Python提高1 第13章 Python提高2 第14章 Mysq|基本使用 第15章 Mysq|查询 第16章Mysql与Python交互 第17章Mysql高级 第18章WSGI-miniWeb框架 第19章闭包装饰器 第20章 mini-web框架 添加路由-MySQL功能 第21章 mini-web框架 添加log日志路由支持正则 第22章元类与ORM-面向接口编程

    diminico_02_1108.pdf

    diminico_02_1108

    基于人工智能大模型技术的果蔬农技知识智能问答系统.pdf

    基于人工智能大模型技术的果蔬农技知识智能问答系统.pdf

    diminico_02_0307.pdf

    diminico_02_0307

    dawe_3cd_01_0717.pdf

    dawe_3cd_01_0717

    anslow_3ck_01_0319.pdf

    anslow_3ck_01_0319

    C#全自动多线程上位机源码编程:替代传统PLC触摸屏、以太网通信,强大功能多级页签,支持西门子PLC和OPC,安装KepserverEx5,链接其他数据库,C#多线程自动化工控屏幕上位机源码编程系统:

    C#全自动多线程上位机源码编程:替代传统PLC触摸屏、以太网通信,强大功能多级页签,支持西门子PLC和OPC,安装KepserverEx5,链接其他数据库,C#多线程自动化工控屏幕上位机源码编程系统:功能强大,多级页签,通信灵活,兼容多种配置与数据库连接,C#全自动多线程上位机源码编程 0, 纯源代码。 1, 替代传统plc搭载的触摸屏。 2, 工控屏幕一体机直接和plc通信。 3, 功能强大,多级页签。 4, 可以自由设定串口或以太网通信。 5, 主页。 6, 报警页。 7, 手动调试页。 8, 参数设定页。 9, 历史查询页。 10,系统设定页。 11, 赠送所有控件。 12,使用的西门子Plc。 13,注册opcdaauto.dll组件,用于使用opc。 15,安装kepserverEx5。 16,可以链接其他数据库。 ,核心关键词: C#; 全自动多线程; 上位机源码编程; 纯源代码; PLC替代; 通信; 强大功能; 多级页签; 串口或以太网通信; 主页; 报警页; 手动调试页; 参数设定页; 历史查询页; 系统设定页; 控件赠送; 西门子PLC; OPC

    移动应用开发全流程解析:从创意到上线与推广的最佳实践

    内容概要:本文详细介绍了移动应用开发的全过程,从创意构思和需求分析开始,依次阐述了原型设计、技术选型、前后端开发、测试优化、上线准备到最后的推广和后续维护,帮助读者深入了解和掌握各个环节的要点和最佳实践,特别注重实际操作中的问题和解决方法。文章不仅涵盖技术层面的内容,还包括市场营销和社会影响等方面的探讨。 适合人群:移动应用开发初学者和有一定经验的开发者,想要了解移动应用从构想直到推向市场全部过程的专业人士。 使用场景及目标:指导新创企业和个体开发者从零开始制作自己的应用程序,提供系统的理论知识以及实用技能指导。 阅读建议:本文适合分章节细读,尤其对于每个关键阶段,可以结合具体的案例研究深入理解;在实践应用时应注意参考文中提到的实际开发中容易碰到的问题及其解决方案。

    axios-v0.18.0

    axios-min.js

    Rust语言教程:从入门到进阶 Rust是一门注重性能、内存安全以及并发的系统编程语言 它被设计用来替代C和C++,同时提供更高的安全性和更好的并发支持 本教程将引导你从Rust的基础语法开始,逐步掌

    Rust语言教程:从入门到进阶 Rust是一门注重性能、内存安全以及并发的系统编程语言。它被设计用来替代C和C++,同时提供更高的安全性和更好的并发支持。本教程将引导你从Rust的基础语法开始,逐步掌握到更高级的概念。 一、Rust入门 1. Rust安装 工具链安装:通过rustup安装Rust工具链,它包含Rust编译器、Cargo包管理器以及标准库文档。 验证安装:在终端运行rustc --version和cargo --version来检查Rust和Cargo是否成功安装。 2. Hello, World! 创建一个新的Rust项目:cargo new hello_world --bin。 进入项目目录:cd hello_world。 编辑srcmain.rs文件,添加fn main() { println!(Hello, World!); }。 编译并运行项目:cargo run。 3. Rust基础语法 变量:使用let关键字声明变量,默认情况下变量是不可变的(immutable)。 数据类型:整数(i32, u32等)、浮点数(f32, f64)、布尔值(bool)、字

    anslow_05_0109.pdf

    anslow_05_0109

    【宝城期货-2025研报】国债期货:国债期货底部震荡为主.pdf

    【宝城期货-2025研报】国债期货:国债期货底部震荡为主.pdf

    dove_02_1106.pdf

    dove_02_1106

    dawe_3cd_02_0717.pdf

    dawe_3cd_02_0717

Global site tag (gtag.js) - Google Analytics