Android AsyncTask

栏目: IOS · Android · 发布时间: 7年前

内容简介:Android AsyncTask
  • Android Studio 2.3
  • API 21

  • 简介和用法

  • RTFSC

AsyncTask 简介

Google介绍

AsyncTask有助于使用UI线程。这个类能让你不主动使用多线程或Handler,在UI线程进行后台操作并发布结果。

AsyncTask是一个在不用多线程和Handler的情况下的帮助类。AsyncTask适用于短时间的操作(最多几秒)。

如需长时间的线程操作,建议使用多线程包 java.util.concurrent 中的API,比如 ExecutorThreadPoolExecutorFutureTask

AsyncTask任务的构成:

  • 3种泛型: ParamsProgressResult
  • 4个步骤: onPreExecute , doInBackground , onProgressUpdateonPostExecute

用法简介

虚构一个计算任务

    /**
     * 虚拟的计算任务
     */
    private class CalculationTaskextends AsyncTask<Float,Integer,Float>{
        protectedFloatdoInBackground(Float... inputs){
            Log.d(TAG, "doInBackground thread ID = " + Thread.currentThread().getId());
            long step = 0;
            float result = 0;
            for (float f : inputs) {
                // 假设这里有一些耗时的操作
                result += f;
            }
            while (step < 5) {
                result += step;
                step++;
                publishProgress((int) step);
            }
            return result;
        }

        protected void onProgressUpdate(Integer... progress){
            Log.d(TAG, "onProgressUpdate thread ID = " + Thread.currentThread().getId());
            Log.d(TAG, "onProgressUpdate: " + progress[0]);
        }

        protected void onPostExecute(Float result){
            Log.d(TAG, "onPostExecute thread ID = " + Thread.currentThread().getId());
            Log.d(TAG, "任务执行完毕");
        }
    }
    // 执行任务
    new CalculationTask().execute(1.2f, 2.3f, 6.3f);
/*
logcat
Main thread ID = 1
doInBackground thread ID = 8089
onProgressUpdate thread ID = 1
onProgressUpdate: 1
...
onProgressUpdate thread ID = 1
onProgressUpdate: 5
onPostExecute thread ID = 1
任务执行完毕
*/

AsyncTask 使用的的泛型

AsyncTask使用的3种泛型

  • Params 送去执行的类型
  • Progress 后台计算的进度类型
  • Result 后台计算的结果

不用的泛型可以用 Void 表示。例如

private class MyTaskextends AsyncTask<Void,Void,Void>{ ... }

异步任务的4个步骤

异步任务执行时经过4个步骤

  • onPreExecute() UI线程在任务开始前调用这个方法。此方法常用来设置任务,比如在屏幕上显示一个进度条。
  • doInBackground(Params...) onPreExecute() 执行完毕后立即在后台线程中执行。这一步用来执行耗时的后台计算。
    这个方法接受异步任务的参数,返回最后的任务结果。这一步可以调用 publishProgress(Progress...) 通知出去一个或多个进度。这些进度值会被 onProgressUpdate(Progress...) 在UI线程收到。
  • onProgressUpdate(Progress...) 调用 publishProgress(Progress...) 后会在UI线程中执行。用来显示执行中任务的UI。
  • onPostExecute(Result) 后台任务执行完毕时被调用。最终结果会被传入这个方法。

取消任务

调用 cancel(boolean) 可随时取消任务。取消任务后 isCancelled() 会返回true。

调用这个方法后,后台任务 doInBackground(Object[]) 执行完毕后会调用 onCancelled(Object) 而不再是 onPostExecute(Object)

为保证任务能被及时地取消,在 doInBackground(Object[]) 中应该经常检查 isCancelled() 返回值

线程规则 Threading rules

一些线程规则

  • 异步任务必须从UI线程启动
  • 必须在UI线程实例化AsyncTask类
  • 必须在UI线程调用 execute(Params...)
  • 不要手动调用 onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)
  • 同一个异步任务实例只能被执行一次。重复执行同一个异步任务实例会抛出异常( IllegalStateException )。

源码简析

AsyncTask是如何调用后台线程完成任务的?线程是如何调度的?

AsyncTask使用 Executor ,利用 WorkerRunnableFutureTask 来执行后台任务

private final WorkerRunnable<Params, Result> mWorker; // 实现了 Callable
private final FutureTask<Result> mFuture;

private static abstract class WorkerRunnable<Params,Result>implements Callable<Result>{
    Params[] mParams;
}

使用 Handler 来进行线程调度。内部定义了一个类 InternalHandler

execute(Params... params) 方法切入

先看方法 execute(Params... params) ,使用默认执行器,并传入参数

调用 xecuteOnExecutor(Executor exec, Params... params)

@MainThread // 指定在主线程执行
public finalAsyncTask<Params, Progress, Result>execute(Params... params){
    return executeOnExecutor(sDefaultExecutor, params);
}

先判断当前状态,如果状态不是 Status.PENDING ,则抛出异常。

否则进入 Status.RUNNING 状态,执行 onPreExecute() ,再由执行器启动任务。

@MainThread
public finalAsyncTask<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();
    mWorker.mParams = params;
    exec.execute(mFuture); // 开始进入后台线程执行任务
    return this;
}

mWorker 带着传进来的参数, mFuture 实例化时已经将 mWorker 注入。参看构造函数

public AsyncTask(){
    mWorker = new WorkerRunnable<Params, Result>() {
        publicResultcall()throwsException{
            mTaskInvoked.set(true);

            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            // 在后台线程进行自定义的操作 这里面可以调用publishProgress方法
            Result result = doInBackground(mParams); 
            Binder.flushPendingCommands();
            return postResult(result); // 发送最终结果
        }
    };

    mFuture = new FutureTask<Result>(mWorker) { // 依赖 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 occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

publishProgress 方法通过主线程的Handler向外通知进度

@WorkerThread
protected final void publishProgress(Progress... values){
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

后台任务执行完毕, postResult 发送最终结果

privateResultpostResult(Result result){
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget(); // 会走到finish方法
    return result;
}

private void finish(Result result){
    if (isCancelled()) {
        onCancelled(result); // 如果任务已经被取消了
    } else {
        onPostExecute(result); // 通知任务执行完毕
    }
    mStatus = Status.FINISHED;
}

关于默认执行器 sDefaultExecutor 和线程池

源码中构建了一个线程池和一个自定义的执行器 SerialExecutor 。靠它们来执行后台任务。

参考源代码

public abstract class AsyncTask<Params,Progress,Result>{
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // 核心线程至少2个,最多4个
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        publicThreadnewThread(Runnable r){
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    public static final Executor THREAD_POOL_EXECUTOR; // 实际执行者

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

    // 默认执行器的类
    private static class SerialExecutorimplements Executor{
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(finalRunnable r){
            mTasks.offer(new Runnable() {
                public void run(){
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext(){
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

电脑报(上下册)

电脑报(上下册)

电脑报社 / 西南师范大学出版社 / 2006-12-01 / 45.00元

全套上、下两册,浓缩2006年电脑报精华文章。附录包含70余篇简明IT应用指南,覆盖软件、硬盘、数码、网络四大领域。配赠权威实用的2006-2007中国计算机年鉴DVD光盘,近1.4GB海量信息与资源超值奉献。8大正版超值软件,涵盖系统维护、系统安全、办公应用、多媒体娱乐等四大领域。微软、腾讯、友立等知名厂商,新年献礼。提供2006-2007全系列硬件、数码产品资讯,兼具知识性与资料性。官方网站全......一起来看看 《电脑报(上下册)》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具