简介

AsyncTask 直接继承于 Object 类,位置为 android.os.AsyncTask。
首先明确 Android 之所以有 Handler 和 AsyncTask ,都是为了不阻塞主线程(UI线程),且 UI 的更新只能在主线程中完成,因此异步处理是不可避免的。Android 的 AsyncTask 比 Handler 更轻量级一些,适用于简单的异步处理。

原理

AsyncTask 是 Android 提供的轻量级的异步类,可以直接继承 AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给 UI 主线程.

特点

优点:

  • 简单,快捷

  • 过程可控

缺点:

  • 在使用多个异步操作和并需要进行 UI 变更时,就变得复杂起来.

使用

参数

AsyncTask 定义了三种泛型参数:

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

方法

  1. 最少重载如下两个方法:
  • doInBackground(Params…)
    后台执行,比较耗时的操作都可以放在这里。
    注意:这里不能直接操作 UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用 publicProgress(Progress…) 来更新任务的进度。
  • onPostExecute(Result)
    相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。
  1. 有必要的话,重载如下三个方法:
    onProgressUpdate(Progress…)
    可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
    onPreExecute()
    这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
    onCancelled()
    用户调用取消时,要做的操作。

使用准则

  • AsyncTask 的实例必须在 UI 线程中创建;
  • execute 方法必须在 UI 线程中调用;
  • 不要直接调用 onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…) 方法;
  • 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常

源码分析

package android.os; import java.util.ArrayDeque;import java.util.concurrent.BlockingQueue;import java.util.concurrent.Callable;import java.util.concurrent.CancellationException;import java.util.concurrent.Executor;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.ThreadFactory;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;import java.util.concurrent.atomic.AtomicBoolean;import java.util.concurrent.atomic.AtomicInteger; public abstract class AsyncTask<Params, Progress, Result> {         private static final String LOG_TAG = "AsyncTask"; //获取当前的cpu核心数    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//线程池核心容量    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;//线程池最大容量    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//过剩的空闲线程的存活时间    private static final int KEEP_ALIVE = 1;//ThreadFactory 线程工厂,通过工厂方法newThread来获取新线程    private static final ThreadFactory sThreadFactory = new ThreadFactory() {     //原子整数,可以在超高并发下正常工作        private final AtomicInteger mCount = new AtomicInteger(1);         public Thread newThread(Runnable r) {                 return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());        }    };//静态阻塞式队列,用来存放待执行的任务,初始容量:128个    private static final BlockingQueue<Runnable> sPoolWorkQueue =            new LinkedBlockingQueue<Runnable>(128);     /**     * 静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务 * 但是我们仍然能构造出并行的AsyncTask     */    public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);     /**     * 静态串行任务执行器,其内部实现了串行控制, * 循环的取出一个个任务交给上述的并发线程池去执行     */    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//消息类型:发送结果    private static final int MESSAGE_POST_RESULT = 0x1;//消息类型:更新进度    private static final int MESSAGE_POST_PROGRESS = 0x2;/**静态Handler,用来发送上述两种通知,采用UI线程的Looper来处理消息 * 这就是为什么AsyncTask必须在UI线程调用,因为子线程 * 默认没有Looper无法创建下面的Handler,程序会直接Crash */    private static final InternalHandler sHandler = new InternalHandler();//默认任务执行器,被赋值为串行任务执行器,就是它,AsyncTask变成串行的了    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//如下两个变量我们先不要深究,不影响我们对整体逻辑的理解    private final WorkerRunnable<Params, Result> mWorker;    private final FutureTask<Result> mFuture;//任务的状态 默认为挂起,即等待执行,其类型标识为易变的(volatile)    private volatile Status mStatus = Status.PENDING;    //原子布尔型,支持高并发访问,标识任务是否被取消    private final AtomicBoolean mCancelled = new AtomicBoolean();//原子布尔型,支持高并发访问,标识任务是否被执行过    private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); /*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的 *目前我们需要知道,asyncTask.execute(Params ...)实际上会调用 *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候, *首先你的task会被加入到任务队列,然后排队,一个个执行 */    private static class SerialExecutor implements Executor {     //线性双向队列,用来存储所有的AsyncTask任务        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//当前正在执行的AsyncTask任务        Runnable mActive;         public synchronized void execute(final Runnable r) {     //将新的AsyncTask任务加入到双向队列中            mTasks.offer(new Runnable() {                     public void run() {                         try {     //执行AsyncTask任务                        r.run();                    } finally {     //当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话//这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务                        scheduleNext();                    }                }            });//如果当前没有任务在执行,直接进入执行逻辑            if (mActive == null) {                     scheduleNext();            }        }         protected synchronized void scheduleNext() {     //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行            if ((mActive = mTasks.poll()) != null) {                     THREAD_POOL_EXECUTOR.execute(mActive);            }        }    }     /**     * 任务的三种状态     */    public enum Status {             /**         * 任务等待执行         */        PENDING,        /**         * 任务正在执行         */        RUNNING,        /**         * 任务已经执行结束         */        FINISHED,    }     /** 隐藏API:在UI线程中调用,用来初始化Handler */    public static void init() {             sHandler.getLooper();    }     /** 隐藏API:为AsyncTask设置默认执行器 */    public static void setDefaultExecutor(Executor exec) {             sDefaultExecutor = exec;    }     /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask() {             mWorker = new WorkerRunnable<Params, Result>() {                 public Result call() throws Exception {                     mTaskInvoked.set(true);                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                return postResult(doInBackground(mParams));            }        };         mFuture = new FutureTask<Result>(mWorker) {                 @Override            protected void done() {                     try {                         postResultIfNotInvoked(get());                } catch (InterruptedException e) {                         android.util.Log.w(LOG_TAG, e);                } catch (ExecutionException e) {                         throw new RuntimeException("An error occured while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                         postResultIfNotInvoked(null);                }            }        };    }     private void postResultIfNotInvoked(Result result) {             final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {                 postResult(result);        }    }//doInBackground执行完毕,发送消息    private Result postResult(Result result) {             @SuppressWarnings("unchecked")        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();        return result;    }     /**     * 返回任务的状态     */    public final Status getStatus() {             return mStatus;    }     /** * 这个方法是我们必须要重写的,用来做后台计算 * 所在线程:后台线程     */    protected abstract Result doInBackground(Params... params);     /** * 在doInBackground之前调用,用来做初始化工作 * 所在线程:UI线程     */    protected void onPreExecute() {         }     /** * 在doInBackground之后调用,用来接受后台计算结果更新UI * 所在线程:UI线程     */    protected void onPostExecute(Result result) {         }     /**     * Runs on the UI thread after {@link #publishProgress} is invoked.     /** * 在publishProgress之后调用,用来更新计算进度 * 所在线程:UI线程     */    protected void onProgressUpdate(Progress... values) {         }      /** * cancel被调用并且doInBackground执行结束,会调用onCancelled,表示任务被取消 * 这个时候onPostExecute不会再被调用,二者是互斥的,分别表示任务取消和任务执行完成 * 所在线程:UI线程     */    @SuppressWarnings({     "UnusedParameters"})    protected void onCancelled(Result result) {             onCancelled();    }            protected void onCancelled() {         }     public final boolean isCancelled() {             return mCancelled.get();    }     public final boolean cancel(boolean mayInterruptIfRunning) {             mCancelled.set(true);        return mFuture.cancel(mayInterruptIfRunning);    }     public final Result get() throws InterruptedException, ExecutionException {             return mFuture.get();    }     public final Result get(long timeout, TimeUnit unit) throws InterruptedException,            ExecutionException, TimeoutException {             return mFuture.get(timeout, unit);    }     /**     * 这个方法如何执行和系统版本有关,在AsyncTask的使用规则里已经说明,如果你真的想使用并行AsyncTask, * 也是可以的,只要稍作修改 * 必须在UI线程调用此方法     */    public final AsyncTask<Params, Progress, Result> execute(Params... params) {     //串行执行        return executeOnExecutor(sDefaultExecutor, params);//如果我们想并行执行,这样改就行了,当然这个方法我们没法改//return executeOnExecutor(THREAD_POOL_EXECUTOR, params);    }     /**     * 通过这个方法我们可以自定义AsyncTask的执行方式,串行or并行,甚至可以采用自己的Executor * 为了实现并行,我们可以在外部这么用AsyncTask: * asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params); * 必须在UI线程调用此方法     */    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,            Params... params) {             if (mStatus != Status.PENDING) {                 switch (mStatus) {                     case RUNNING:                    throw new IllegalStateException("Cannot execute task:"                            + " the task is already running.");                case FINISHED:                    throw new IllegalStateException("Cannot execute task:"                            + " the task has already been executed "                            + "(a task can be executed only once)");            }        }         mStatus = Status.RUNNING;//这里#onPreExecute会最先执行        onPreExecute();         mWorker.mParams = params;//然后后台计算#doInBackground才真正开始        exec.execute(mFuture);//接着会有#onProgressUpdate被调用,最后是#onPostExecute         return this;    }     /**     * 这是AsyncTask提供的一个静态方法,方便我们直接执行一个runnable     */    public static void execute(Runnable runnable) {             sDefaultExecutor.execute(runnable);    }     /** * 打印后台计算进度,onProgressUpdate会被调用     */    protected final void publishProgress(Progress... values) {             if (!isCancelled()) {                 sHandler.obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();        }    } //任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用    private void finish(Result result) {             if (isCancelled()) {                 onCancelled(result);        } else {                 onPostExecute(result);        }        mStatus = Status.FINISHED;    } //AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息    private static class InternalHandler extends Handler {             @SuppressWarnings({     "unchecked", "RawUseOfParameterizedType"})        @Override        public void handleMessage(Message msg) {                 AsyncTaskResult result = (AsyncTaskResult) msg.obj;            switch (msg.what) {                     case MESSAGE_POST_RESULT:                    // There is only one result                    result.mTask.finish(result.mData[0]);                    break;                case MESSAGE_POST_PROGRESS:                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }    }     private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {             Params[] mParams;    }     @SuppressWarnings({     "RawUseOfParameterizedType"})    private static class AsyncTaskResult<Data> {             final AsyncTask mTask;        final Data[] mData;         AsyncTaskResult(AsyncTask task, Data... data) {                 mTask = task;            mData = data;        }    }}

实例

  1. 逻辑代码
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity">    <TextView        android:id="@+id/show"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="还没开始下载呢"        app:layout_constraintBottom_toBottomOf="parent"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toRightOf="parent"        app:layout_constraintTop_toTopOf="parent" />    <ProgressBar        android:id="@+id/progressBar"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginStart="14dp"        android:layout_marginLeft="14dp"        android:layout_marginBottom="34dp"        app:layout_constraintBottom_toTopOf="@+id/show"        app:layout_constraintStart_toStartOf="@+id/show" />    <Button        android:id="@+id/btn_start"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginStart="8dp"        android:layout_marginLeft="8dp"        android:layout_marginTop="32dp"        android:layout_marginEnd="8dp"        android:layout_marginRight="8dp"        android:text="开始下载"        app:layout_constraintEnd_toStartOf="@+id/show"        app:layout_constraintStart_toStartOf="parent"        app:layout_constraintTop_toBottomOf="@+id/show" />    <Button        android:id="@+id/btn_cancel"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginStart="8dp"        android:layout_marginLeft="8dp"        android:layout_marginTop="31dp"        android:layout_marginEnd="8dp"        android:layout_marginRight="8dp"        android:text="取消"        app:layout_constraintEnd_toEndOf="parent"        app:layout_constraintStart_toEndOf="@+id/show"        app:layout_constraintTop_toBottomOf="@+id/show" />android.support.constraint.ConstraintLayout>
  • 自定义 AsyncTask
/** * Created on 2019/4/8 11:17 * * @author Scarf Gong */public class MyTask extends AsyncTask<String,Integer,String> {         private Button button,cancel; // 加载、取消按钮    private TextView text; // 更新的UI组件    private ProgressBar progressBar; // 进度条    public MyTask(Button button, Button cancel, TextView text, ProgressBar progressBar) {             this.button = button;        this.cancel = cancel;        this.text = text;        this.progressBar = progressBar;    }    @Override    protected String doInBackground(String... strings) {             try {                 int count = 0;            int length = 1;            while (count < 99) {                     count += length;                // 可调用publishProgress()显示进度, 之后将执行onProgressUpdate()                publishProgress(count);                // 模拟耗时任务                Thread.sleep(50);            }        }catch (InterruptedException e) {                 e.printStackTrace();        }        return null;    }    @Override    protected void onPreExecute() {             text.setText("loading");    }    @Override    protected void onProgressUpdate(Integer... values) {             progressBar.setProgress(values[0]);        text.setText("loading..." + values[0] + "%");    }    @Override    protected void onPostExecute(String s) {             text.setText("complete");    }    @Override    protected void onCancelled() {             text.setText("click cancel");        progressBar.setProgress(0);    }}
  • 在 MainActivity.java 中使用
package com.scarf.asynctaskdemo;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.ProgressBar;import android.widget.TextView;public class MainActivity extends AppCompatActivity {         private Button button,cancel; // 加载、取消按钮    private TextView text; // 更新的UI组件    private ProgressBar progressBar; // 进度条    private MyTask mTask;    @Override    protected void onCreate(Bundle savedInstanceState) {             super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        mTask = new MyTask(button,cancel,text,progressBar);        button.setOnClickListener(new View.OnClickListener() {                 @Override            public void onClick(View v) {                     mTask.execute();            }        });        cancel.setOnClickListener(new View.OnClickListener() {                 @Override            public void onClick(View v) {                     mTask.cancel(true);            }        });    }    private void initView() {             button = findViewById(R.id.btn_start);        cancel = findViewById(R.id.btn_cancel);        progressBar = findViewById(R.id.progressBar);        text = findViewById(R.id.show);    }}
  1. 效果图
    Android 多线程之 AsyncTask_第1张图片

更多相关文章

  1. Android编程简单设置ListView分割线的方法
  2. android主线程和子线程的区别
  3. 怎么让 Android 程序一直后台运行,像 QQ 一样不被杀死?
  4. Android Studio的Gradle文件方法说明
  5. 获取Android SDK 源代码并在Eclipse中关联查看的方法

随机推荐

  1. Android隐藏软键盘
  2. Android(安卓)使用ContentProvider 添加
  3. Android搜索框自动提示文本框——(单一提
  4. Android(安卓)source download for linux
  5. Android(安卓)WiFi管理(WIFI_SERVICE)
  6. Android进度条简单练习实例
  7. How to resign the Android(安卓)APK
  8. android 开机启动
  9. Android(安卓)VideoView播放视频
  10. android 开发