AsyncTask笔记

在学习Android的时候,我们用到比较多的异步处理的类大概就是AsyncTask,但是很多时候只知道调用,却不知道思考一些东西。

本文就简单的总结和分析了一些AsyncTask的知识。

一、AsyncTask使用

实现自己的AsyncTask

1.继承AsyncTask

public abstract class AsyncTask 
  • Params表示AsyncTask执行任务的参数的类型(传入的参数的类型,在doInBackground用到的,使用execute方法中传入)
  • Progress表示在后台线程处理的过程中,可以阶段性地发布结果的数据类型(在onProgressUpdate中用到,使用publicProgress中传入)
  • Result表示任务全部完成后所返回的数据类型(doInBackground方法的返回值)
  1. 必须实现的方法:
protected abstract Result doInBackground(Params... params);
  • 这个方法是AsyncTask最关键的地方,里面实现异步代码来执行异步的操作
  1. 可实现方法
//异步执行之前也就是doInBackground之前执行
protected void onPreExecute()
//异步执行之后也就是doInBackground之后执行
protected void onPostExecute(Result result)
//执行过程中执行
protected void onProgressUpdate(Progress... values) 
  • 这3个方法是在主线程执行的,所有可以更新UI

具体调用方法

public final AsyncTask execute(Params... params) {
execute方法,每次只能执行一个线程,不支持并发。
public final AsyncTask executeOnExecutor(Executor exec,
        Params... params) {
executeOnExecutor可以添加自己的线程池,是可以支持并发的。

注意事项

  • AsyncTask的实例必须在主线程中创建。
  • AsyncTask的execute方法必须在主线程中调用。
  • onPreExecute()、onPostExecute(Result),、doInBackground(Params…) 和 onProgressUpdate(Progress…)这四个方法都是回调方法,Android会自动调用,我们不要自己调用。
  • 对于一个AsyncTack的实例,只能执行一次execute,在该实例上第二次执行execute时就会抛出异常。

前两条基本是一个意思,就是使用AsyncTask的时候在UI线程中创建/执行;4个主要的方法不能在外部去调用;因为execute不支持并发,所有不能调用第二次,executeOnExecutor是可以多次调用的。

二、源码分析

AsyncTask主要是通过线程池+handler来实现。
线程池:

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    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; 

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    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;
    }
  • 使用ThreadPoolExecutor创建一个线程池,这线程池的核心线程是动态的,根据cpu的数量来定(2-4)个,在4.4之前的核心线程数是5。
    private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();
        Runnable mActive;

        public synchronized void execute(final Runnable 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);
            }
        }
    }
  • 把Runnable放入双端队列末尾,交给线程池去处理。(java.util.ArrayDeque.offer(E e) 方法将指定元素E在此deque队列的末尾。
    java.util.ArrayDeque.poll() 检索并移除此queue队列表示的队列的头部,如果此queue队列为空,返回null)

具体线程:

 mWorker = new WorkerRunnable() {
        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(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);
            }
        }
    };
  • 主要就是这个FutureTask+Callable实现了异步线程,WorkerRunnable 实现了Callable接口。(实现多线程的方式有几种?可能现在需要多记一种Callable)
    使用的Handler:
    private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @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;
            }
        }
    }
  • 在实例化AsyncTask的时候会去准备好线程池、线程和handler,在execute执行的时候把线程扔到线程池中执行,执行中可以发送数据给handler(publishProgress),结束后发消息给handler(postResult)。

总结

  • execute方法会调用executeOnExecutor方法,使用的线程池还是默认的
  • executeOnExecutor和execute在UI线程执行,那么里面调用的所有方法也是在UI线程中,所以onPreExecute()方法在UI线程中
  • handler使用的是UI线程的looper = Looper.getMainLooper(),那么Handler的handleMessage方法在UI线程中,所以onPostExecute和onProgressUpdate在UI线程中。

(文章移植自己的博客园:AsyncTask)快乐每一天

你可能感兴趣的:(AsyncTask笔记)