Android AsyncTask

343 阅读4分钟

基本介绍

AsyncTask的作用

AsyncTask源码中的注释: AsyncTask让使用UI线程简单正确, 该类允许你在后台执行操作并将结果发布到UI线程同时避免使用handler。

AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

AsyncTask使用的注意事项

  • 类必须在UI线程中加载 (高版本好像没这个限制了)

  • 实例必须在UI线程中创建(要通过ThreadLocal拿到主线程的Looper)

  • execute方法必须在UI线程中调用(会回调 onPreExecute)

  • 任务只能执行1次, 再次执行会抛异常

AsyncTask Demo

AsyncTask<Void, Integer, Integer> task = new AsyncTask<Void, Integer, Integer>() {
    @Override
    protected Integer doInBackground(Void... voids) {
        int i = 0;
        while (i <= 100) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
            publishProgress(i);
        }

        return i;
    }

    @Override
    protected void onPreExecute() {
        // 进度条可见
        pb.setMax(100);
        pb.setVisibility(View.VISIBLE);
        tv.setText("do asyn task");
    }


    @Override
    protected void onPostExecute(Integer integer) {
        pb.setVisibility(View.INVISIBLE);
        tv.setText("task done!");
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        pb.setProgress(values[0]);
        tv.setText("progress : " + values[0]);
    }
};
task.execute();

AsyncTask源码分析

构造方法

无参构造、带一个Handler的构造和带一个Looper的构造最终都会调用带一个Looper的构造方法

public AsyncTask(@Nullable Looper callbackLooper) {
    // 获取Handler
    // 因为AsyncTask在UI线程中创建, 所以前面的条件满足, 会进入getMainHandler方法
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()
        : new Handler(callbackLooper);

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);
            }
            return result;
        }
    };

    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 occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

// Looper是UI线程的Looper, 最终在UI线程中调用Handler的方法处理消息
private static Handler getMainHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            // 创建一个InternalHandler的Handler并返回
            sHandler = new InternalHandler(Looper.getMainLooper());
        }
        return sHandler;
    }
}

InternalHandler对象

InternalHandler是AsyncTask的静态内部类

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }


    @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:
                // 这个消息会在publishProgress中发出来
                // 如果是发布更新的消息则调用AsyncTask对应的onProgressUpdate回调方法
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

execute方法

execute方法在内部调用了executeOnExecutor方法, 顾名思义通过Executor来执行task, 传入一个SerialExecutor类型的实例来执行任务

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

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 和 onPostExecute 方法中显示和关闭比如进度条等UI空间
    // 所以要求execute方法在UI线程中执行, onPostExecute会在任务结束时 handler的handMessage方法中回调
    onPreExecute();
    mWorker.mParams = params;
    // 通过Executor来执行, 上面传递的是 sDefaultExecutor (SerialExecutor类型的实例)
    exec.execute(mFuture);
    return this;
}

SerialExecutor

AsyncTask的内部类, 实现 java.util.concurrent.Executor 接口, 由SerialExecutor类的源码可以看到所有提交的任务被放到一个队列中进行排队, 每次获取一个任务进行执行, SerialExecutor只是将任务进行一个排队操作, 最终任务被交给THREAD_POOL_EXECUTOR去执行。

private static class SerialExecutor implements Executor {
    // 任务队列
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        // 构造一个Runnable实例, 执行完任务之后自动调用scheduleNext获取下一个任务并执行
        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执行任务
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

THREAD_POOL_EXECUTOR

由源码可以看到 THREAD_POOL_EXECUTOR 是AsyncTask类中的一个静态常量, 通过static代码块来初始化, 是ThreadPoolExecutor的一个实例, 代表一个线程池

public static final Executor THREAD_POOL_EXECUTOR;

static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>(), sThreadFactory);
    threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

executeOnExecutor(Executor exec, Params... params)方法

上面提到excute方法内部调用executeOnExecutor方法来执行任务, 而executeOnExecutor内部默认使用SerialExecutor执行任务, 因此AsyncTask的任务都是串行执行的, 如果想要任务并发执行, 可以直接调用executeOnExecutor方法并将THREAD_POOL_EXECUTOR作为参数传递。

publishProgress 方法

doInBackground方法中可以通过publishProgress发布当前的任务进度

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        // 获取到Handler, 改造一条Message, Message的taget为该Handler
        // 调用Message的sendToTarget方法, 利用Handler发送消息
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}