前言

在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, ProgressResult


   - 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"?>                                                                                                                                                              


在以上的main.xml文件中,我们主要定义了一个EditText,用于输入需要计数的时间;一个TextView,用于显示计数的变化; 和一个Button,用于启动计数任务。


在我们的类AsyncTaskActivity中,我们首先声明三个private变量,对应以上三个元素。


private Button start;private TextView chronoText;private EditText chronoValue;


然后创建一个内部类,继承AsyncTask类,命名为“Chronograph”,就是秒表或计时器。


private class Chronograph extends AsyncTask {    @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方法:

@Overridepublic 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 {...}


运行我们的项目,可以得到如下面三张图所示的结果:


Figure 2: 按下Start按钮前





Figure 3: 计数中



Figure 4: 计数后



总结

今后,当有异步任务需要执行时,可以使用AsyncTask类,可以根据自己的需要来定制。


AsyncTask使用了线程池(Thread Pool)的机制,使得同时执行多个AsyncTask成为可能。但是要注意的是,这个线程池的容量是5个线程同时执行,如果超过了这个数量,多余的线程必须等待线程池里的线程执行完才能启动。


因此,使用AsyncTask,最好在明确知道任务会有一个确定和合理的结束的情况下。否则,还是使用传统的Thread类为好。



附: 实例项目源码

更多相关文章

  1. Android(安卓)RxJava系列一: 基础常用详解
  2. Android(安卓)一套完整的 Socket 解决方案
  3. Fragment使用总结
  4. Android弱网测试中关于网络检测的一些借鉴方法
  5. android 模拟器创建的sdcard 没有mount
  6. 2011.12.05(7)——— android JNI学习之六 JNI的一个框架
  7. Android实现多线程下载图片的方法
  8. ADB适用方法
  9. android艺术开发探索之RemoteViews跨进程更新UI

随机推荐

  1. 速写人物如何学习?速写人物学习画法
  2. phpstorm最新激活码分享亲测phpstorm2021
  3. 清除移动端网站点击a标签时闪现的边框或
  4. PHP获取真实IP及IP模拟方法解析
  5. 使用python 中的socket包实现本地电脑与
  6. Centos系统部署nginx1.18.0
  7. 访问器属性与获取DOM元素的两种方法
  8. 如何开始学基础画画?0基础学画画教程!
  9. 深入聊一聊JS中new的原理与实现
  10. 在Ubuntu20.04上安装Kubernetes-Kubeadm