用AsyncTask实现多线程
前言
在Android应用开发中,有时我们需要实现任务的同步。Android里的AsyncTask类可以帮我们更好地管理线程同步(异步方式),就像Thread类能做的,不过用法比Thread更简单。
这篇博文包含以下两个部分:
1、AsyncTask介绍
2、实例
一、 AsyncTask介绍
在你开发Android应用程序时,如果在一个Activity里有一个耗时任务(通常是一个子线程),并且这个任务调用/操作了主线程,应用就会抛出著名的“ANR” (Application
Not Responding)错误。

Figure 1: ANR
AsyncTask类可以帮我们解围,使用AsyncTask能让我们正确及简便地使用主线程,即使此时另有一个异步线程被创建。它使得耗时任务可以在后台执行,并在前台(UI线程或主线程)把执行结果展现出来,不必用到Thread类或Handler类。线程间通信也随之变得更简单,优雅。
* 主线程(User Interface Thread UI线程)是在Android里负责和用户界面进行交互的线程。
AsyncTask是一个抽象类,必须被继承才能实例化。有三个泛型参数,分别是:
Params, Progress 和
Result:
-
Params : 传递给执行的任务的参数,也就是doInBackground方法的参数。
-
Progress : 后台任务执行过程中在主线程展现更新时传入的参数,也就是onProgressUpdate方法的参数。
-
Result : 后台执行的任务返回的结果,也就是onPostExecute方法的参数。
除此之外,继承AsyncTask类时,一般需要实现四个方法。当然应用程序不需要调用这些方法,这些方法会在任务执行过程中被自动调用: onPreExecute, doInBackground, onProgressUpdate 和 onPostExecute (其中的doInBackground抽象方法必须要被子类重写):
-
onPreExecute : 此方法在主线程中执行,用于初始化任务。
-
doInBackground : 此方法在后台执行。此方法在onPreExecute方法执行完后启动。这个方法中执行的操作可以是耗时的,并不会阻塞主线程。通过调用publishProgress方法来在主线程显示后台任务执行的结果更新。
-
onProgressUpdate : 此方法也在主线程中执行,每当publishProgress方法被调用时,此方法就被执行,此方法只在doInBackground执行过程中才能被调用。
-
onPostExecute : 在doInBackground方法执行完之后启动的方法,在后台任务结束后才调用此方法,也在主线程执行。
二、 实例
为了更好地展现AsyncTask的使用,我们来实现一个计时器的小应用。首先我们创建一个Android项目,就命名为“AsyncTaskActivity”好了(名字无所谓),修改 res->layout 里的定义主用户界面的 xml 文件:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="15dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="5dp"
android:text="Time in min"
android:textSize="18dp"
android:textStyle="bold" />
<EditText
android:id="@+id/chronoValue"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginBottom="15dp"
android:layout_gravity="center"
android:hint="minutes"
android:inputType="number"
android:singleLine="true"
android:text="1"
android:textSize="15dp" />
<TextView
android:id="@+id/chronoText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="0:0"
android:textSize="80dp" />
<Button
android:id="@+id/start"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="Start" />
</LinearLayout>
在以上的main.xml文件中,我们主要定义了一个EditText,用于输入需要计数的时间;一个TextView,用于显示计数的变化; 和一个Button,用于启动计数任务。
在我们的类AsyncTaskActivity中,我们首先声明三个private变量,对应以上三个元素。
private Button start; private TextView chronoText; private EditText chronoValue;
然后创建一个内部类,继承AsyncTask类,命名为“Chronograph”,就是秒表或计时器。
private class Chronograph extends AsyncTask<Integer, Integer, Void> {
@Override
protected void onPreExecute() {
super.onPreExecute();
// Disable the button and edittext before the start of the deduction
chronoValue.setEnabled(false);
start.setEnabled(false);
chronoText.setText("0:0");
}
@Override
protected Void doInBackground(Integer... params) {
// Deduction
for (int i = 0; i <= params[0]; i++) {
for (int j = 0; j < 60; j++) {
try {
// Publication of increment
publishProgress(i, j);
if (i == params[0]) {
return null;
}
// Pause for one second
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (isCancelled()) {
return null;
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Update on the User Interface
chronoText.setText(values[0] + ":" + values[1]);
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Reactivation of the button and edittext
chronoValue.setEnabled(true);
start.setEnabled(true);
}
}
以上,我们重写了我们需要的四个方法。最后我们再完成我们AsyncTaskActivity类的onCreate方法:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Recuperation of the usable components
start = (Button)findViewById(R.id.start);
chronoText = (TextView)findViewById(R.id.chronoText);
chronoValue = (EditText)findViewById(R.id.chronoValue);
start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Recuperation of the value in the EditText
int value = Integer.parseInt(String.valueOf(chronoValue.getText()));
// Verification of the content
if (value > 0) {
new Chronograph().execute(value);
}
else {
Toast.makeText(AsyncTaskActivity.this, "Please enter a correct value !", Toast.LENGTH_LONG).show();
}
}
});
}
如果我们在继承AsyncTask类时,对于三个参数中有不需要的,可以定义为Void类型(注意,与小写的 void 不同),例如:
private class Chronograph extends AsyncTask<Integer, Integer, Void> {...}
运行我们的项目,可以得到如下面三张图所示的结果:
Figure 2: 按下Start按钮前
Figure 3: 计数中
Figure 4: 计数后
总结
今后,当有异步任务需要执行时,可以使用AsyncTask类,可以根据自己的需要来定制。
AsyncTask使用了线程池(Thread Pool)的机制,使得同时执行多个AsyncTask成为可能。但是要注意的是,这个线程池的容量是5个线程同时执行,如果超过了这个数量,多余的线程必须等待线程池里的线程执行完才能启动。
因此,使用AsyncTask,最好在明确知道任务会有一个确定和合理的结束的情况下。否则,还是使用传统的Thread类为好。
附: 实例项目源码
百度云盘下载链接:http://pan.baidu.com/s/1sj36O5v
用AsyncTask实现多线程的更多相关文章
- AsyncTask实现多线程断点续传
前面一篇博客<AsyncTask实现断点续传>讲解了如何实现单线程下的断点续传,也就是一个文件只有一个线程进行下载. 对于大文件而言,使用多线程下载就会比单线程下载要快一些.多线程下载 ...
- 解决Android中AsyncTask的多线程阻塞问题
Android开发中执行耗时操作并更新UI时,通常有三种方式:1.直接调用runOnUiThread(new Runnable(){}),使用简单,但不能在Activity之外的环境使用,如View. ...
- AsyncTask实现多任务多线程断点续传下载
这篇博客是AsyncTask下载系列的最后一篇文章,前面写了关于断点续传的和多线程下载的博客,这篇是在前两篇的基础上面实现的,有兴趣的可以去看下. 一.AsyncTask实现断点续传 二.AsyncT ...
- android 多线程下载 断点续传
来源:网易云课堂Android极客班第八次作业练习 练习内容: 多线程 asyncTask handler 多线程下载的原理 首先获取到目标文件的大小,然后在磁盘上申请一块空间用于保存目标文件,接着把 ...
- 【AsyncTask整理 1】 AsyncTask几点要注意的地方
问题1:AsyncTask是多线程吗? 答:是. 问题2:AsyncTask与Handler相比,谁更轻量级? 答:通过看源码,发现AsyncTask实际上就是一个线程池,而网上的说法是AsyncTa ...
- Android 开发中三种多线程
在开发工程中线程可以帮助我们提高运行速度,Android开发中我知道的线程有四个一个是老生长谈的Thread,第二个是asyncTask,第三个:TimetTask,第四个是Looper,四个多线程各 ...
- android代码片段二
1.Android拦截短信 一.AndroidManifest.xml <uses-permission android:name="android.permission.RECE ...
- Android 线程_笔记
多线程 一.为什么要使用多线程 1.提高用户体验或避免ANR 在事件处理代码中需要使用多线程,响应时间超过5s,即会出现ANR(Application is not responding),并因为响应 ...
- Android异步载入全解析之大图处理
Android异步载入全解析之大图处理 异步载入中很重要的一部分就是对图像的处理,这也是我们前面用异步载入图像做示例的原因. 一方面是由于图像处理不好的话会很占内存,并且easyOOM,还有一方面,图 ...
随机推荐
- (hdu 简单题 128道)平方和与立方和(求一个区间的立方和和平方和)
题目: 平方和与立方和 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- ftk学习记(waitbox篇)
[声明:版权全部.欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 前面说到了脚本.那么就看看ftk中demo与script搭配的效果是什么样的? 上面的效果图就相 ...
- JDBC数据库连接
JDBC是什么? Java Data Base Connectivity JDBC是: 以统一方式訪问数据库的API,能够訪问不论什么类型表列数据.特别是存储在关系数据中的数据.JDBC代表Java数 ...
- Mit 分布式系统导论,Distributed Systems ,lab1 -lab6 总结,实验一到实验六总结
终于把Mit的分布式系统导论课的实验1-6写完了 做得有些痛苦,但是收获也很大 http://pdos.csail.mit.edu/6.824-2012/labs/index.html 把实验1-6用 ...
- 本地或者服务器同时启动2个或多个tomcat
一,修改配置文件server.xml的端口 C:\apache-tomcat-5.5.23-1\conf\server.xml用记事本什么的打开修改3个地方 第一: <Server port ...
- vmware: The file system upon which * resides is critically low on free space.
The file system upon which ******.localized/Windows XP Professional.vmwarevm' resides is critically ...
- Nginx安装手冊以及图片server部署
1. 安装gcc yum install gcc 2. 安装pcre,pcre-devel 在zhoulh文件夹下建立source build文件夹 mkdir source bu ...
- POJ 1515 Street Directions
题意: 一幅无向图 将尽量多的无向边定向成有向边 使得图强连通 无向图保证是连通的且没有重边 思路: 桥必须是双向的 因此先求边双连通分量 并将桥保存在ans中 每一个双连通分量内的边一定都 ...
- uvalive 2911 Maximum(贪心)
题目连接:2911 - Maximum 题目大意:给出m, p, a, b,然后xi满足题目中的两个公式, 要求求的 xp1 + xp2 +...+ xpm 的最大值. 解题思路:可以将x1 + x2 ...
- java 线程 新类库中的构件 countDownLatch 使用
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmdydWkxOTg4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...