用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

时间: 2024-08-10 09:35:54

用AsyncTask实现多线程的相关文章

AsyncTask实现多线程断点续传

前面一篇博客<AsyncTask实现断点续传>讲解了如何实现单线程下的断点续传,也就是一个文件只有一个线程进行下载.   对于大文件而言,使用多线程下载就会比单线程下载要快一些.多线程下载相比单线程下载要稍微复杂一点,本博文将详细讲解如何使用AsyncTask来实现多线程的断点续传下载. 一.实现原理 多线程下载首先要通过每个文件总的下载线程数(我这里设定5个)来确定每个线程所负责下载的起止位置. long blockLength = mFileLength / DEFAULT_POOL_SI

AsyncTask、多线程及线程通信

AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单.相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现. AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result. Params 启动任务执行的输入参数,比如HTTP请求的URL. Progress 后台任务执行的百分比. Result 后台执行任务最终返回的结果,比如String. AsyncTask的执行分为四个步骤

Android 开发中三种多线程

在开发工程中线程可以帮助我们提高运行速度,Android开发中我知道的线程有四个一个是老生长谈的Thread,第二个是asyncTask,第三个:TimetTask,第四个是Looper,四个多线程各有个的有点,Thread的运行速度是最快的,AsyncTask的规范性是最棒的,其它两个也有自己的优点. 1.Thread与Handler组合,比较常见 Handler主要是帮助我们来时时更新UI线程 这里在后天加载100张图片,然后没加载完成一个用handler 返回给UI线程一张图片并显示 最后

Android研究之游戏开发多线程详解

 游戏开发与软件开发多线程的重要性       如果程序主线程被阻塞超过5秒,系统会提示"应用程序无响应" 这就是ANR . ANR的全称是Application Not Responding,使用多线程可以避免ANR.但是这里要注意一下不要为了避免ANR而过多的使用多线程,除非万不得已的情况. 比如访问网络服务端返回的过慢.数据过多导致滑动屏幕不流畅.或者I/O读取过大的资源等等.这里可以开启一个新线程来处理这些耗时的操作. 如果过多使用多线程会出现数据同步的问题须要程序员去处理

Android-异步任务介绍及面试题

Android-异步任务 一 什么是AsyncTask Android为了减低异步操作的开发难度,结合Handle和线程池,提供了AsyncTask.AsyncTask就是一个封装过的后台任务类, 顾名思义就是异步任务,他具有可以在后台执行耗时操作,同时可以将 执行的进度与UI进行同步的优点 因为Handle实际上就是两个线程之间的桥梁,但是数据的传递是单向的 Handle机制如下图: 而AsyncTask机制如下: 二 如何使用AsyncTask AsyncTask定义三种泛型类型Params

Android异步加载全解析之大图处理

Android异步加载全解析之大图处理 异步加载中非常重要的一部分就是对图像的处理,这也是我们前面用异步加载图像做演示例子的原因.一方面是因为图像处理不好的话会非常占内存,而且容易OOM,另一方面,图像也比文字要大,加载比较慢.所以,在讲解了如何进行多线程.AsyncTask进行多线程加载后,先暂停下后面的学习,来对图像的异步处理进行一些优化工作. 为什么要对图像处理 为什么要对图像进行处理,这是一个很直接的问题,一张图像,不管你拿手机.相机.单反还是什么玩意拍出来,它就有一定的大小,但是在不同

Android异步载入全解析之大图处理

Android异步载入全解析之大图处理 异步载入中很重要的一部分就是对图像的处理,这也是我们前面用异步载入图像做示例的原因. 一方面是由于图像处理不好的话会很占内存,并且easyOOM,还有一方面,图像也比文字要大,载入比較慢.所以,在解说了怎样进行多线程.AsyncTask进行多线程载入后,先暂停下后面的学习.来对图像的异步处理进行一些优化工作. 为什么要对图像处理 为什么要对图像进行处理,这是一个很直接的问题.一张图像.无论你拿手机.相机.单反还是什么玩意拍出来,它就有一定的大小,可是在不同

android代码解析之图片缓存(ImageDownloader)

在android代码里development/samples有一个工具类:ImageDownloader,其作用是从网上下载图片显示到给定的ImageView.如下时原文说明: This helper class download images from the Internet and binds those with the provided ImageView. 这里来解析一下这个工具类是如何实现的,下面一个一个来解释. (1)首先,他采用了强引用(StrongReference)和软引用

步步为营_Android开发课[7]_AsyncTask学习

Focus on technology, enjoy life!-- QQ:804212028 浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:AsyncTask学习 -在开发Android移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验.但是在子线程中无法去操作主线程(UI线程),在子线程中操作UI线程会出现错误.因此androi