AsyncTask那些事

694 阅读6分钟

1、简介

是android为开发者封装好的,异步轻量级任务执行框架;

如果你因为可能的内存泄漏问题而不使用,我想说大可不必,自己封装基本并比不上系统的;再者说,如果使用了线程都可能造成内存泄漏问题,这个是由gc清除对象时处理造成的,使用线程的场景到处都是

从代码角度来看其实现,内部是使用了线程池+FutureTask+Handle来实现的;所以我们就来看看它对线程池、FutureTask使用的处理

2、线程池使用

2.1 SERIAL_EXECUTOR线程池

公有静态常量,就是顺序执行线程池对象;其顺序执行阈值为Runnable mActive,其并不是线程安全的,所以,只能保证单线程中顺序执行,多线程也是可能并发执行的;mActive == null条件表示队列中没有可执行的任务

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        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);
            }
        }
    }
}

线程执行流程:

  • 第一次执行任务时,直接调用THREAD_POOL_EXECUTOR线程池直接执行
  • 非首次执行任务时,会查看已经执行过任务从队列中取出任务是否为空,来决定是否执行;

也就是说,队列中任务执行,可能是上次任务执行完毕后继续执行,或者任务队列为空直接执行

2.2 THREAD_POOL_EXECUTOR线程池

公有静态常量,特点:

  • 单核心,多个可缓存线程的线程池;可用线程最大数为20
  • 可存活时间3s
  • 任务队列使用容器为0的SynchronousQueue队列
  • 线程名字打上AsyncTask标签
  • 任务拒绝策略由sBackupExecutor来执行;sBackupExecutor是仅有5个核心线程的线程池,队列个数整数最大,核心线程可销毁,线程仍然线程名字打上AsyncTask标签
    private static final int CORE_POOL_SIZE = 1;
    private static final int MAXIMUM_POOL_SIZE = 20;
    private static final int BACKUP_POOL_SIZE = 5;
    private static final int KEEP_ALIVE_SECONDS = 3;
    
    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());
        }
    };
    
    private static final RejectedExecutionHandler sRunOnSerialPolicy =
            new RejectedExecutionHandler() {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
            synchronized (this) {
                if (sBackupExecutor == null) {
                    sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
                    sBackupExecutor = new ThreadPoolExecutor(
                            BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
                            TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
                    sBackupExecutor.allowCoreThreadTimeOut(true);
                }
            }
            sBackupExecutor.execute(r);
        }
    };
    
    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;
    }

直白点说

  • 如果一直在主线程使用,那么任务是一个顺序执行的
  • 顺序执行线程池使用代理的使用,由一个由1个核心,19个可缓存,队列容量为0的线程池代理
  • 如果发生并发的话,最多同时执行任务25个,多余的任务在拒绝策略中处理
  • 拒绝策略由5个存活时间有限的核心线程,且队列无界的线程池来执行;基本不会抛弃任务

3、源码分析

介绍一些主要方法和流程,其余的方法,如果有兴趣可以执行了解

3.1 构造器

public AsyncTask() {
        this((Looper) null);
    }

    public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }

    public AsyncTask(@Nullable Looper callbackLooper) {
        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);
                    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);
                }
            }
        };
    }
  • 消息传播handler对象,默认是主handler,也可以自由传入;自由传入无视了下面消息
    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;
  • mWorker 是线程具体执行,执行doInBackground(mParams),并用postResult发布结果
  • mFuture 中done方法,无论线程执行的什么样,都会调用,确保调用postResult发布结果

postResult方法

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

消息 what = MESSAGE_POST_RESULT,obj为AsyncTaskResult对象,其包含AsynTask当前对象和doInBackground(mParams)执行结果

3.2 主线程消息处理

主线程消息,是内部类InternalHandler对象

    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:
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
  • MESSAGE_POST_RESULT消息:任务执行完毕发送此消息
  • MESSAGE_POST_PROGRESS消息:publishProgress方法被调用时发出此消息

消息具体执行动作

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

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
  • MESSAGE_POST_RESULT消息:如果用户取消了任务,回调onCancelled,否则回调onPostExecute方法
  • MESSAGE_POST_PROGRESS消息:回调onProgressUpdate方法,空方法,需要继承实现

3.3 执行任务

可以分为三种情况:使用默认线程池(顺序执行)执行异步任务、自定义线程池执行异步任务、默认线程池执行任何Runnable任务;三种任务中,我们经常使用默认线程池执行异步任务;

    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();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }
    
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }

异步任务流程:

  • 判断状态,如果已经运行或者结束,则抛出异常;状态有三种,由内部类Status定义:未运行,正在运行,运行结束
    public enum Status {
        PENDING,
        RUNNING,
        FINISHED,
    }
  • 首先执行onPreExecute方法,空方法,可以自定义实现,在调用线程中执行
  • 然后才使用线程池执行任务

4、原理总结

  1. 这个是特意为主线程设计的轻量级、异步执行主线程获取结果的框架;为何这么说,最简单的原因,非主线程不能获取消息,不能处理进度信息,其结果获取也得通过get方法获取,这和FutureTask使用的没有太大区别
  2. 异步中涉及的一些方法执行:这些都是空实现,如有需要需要自实现
  • onPreExecute 执行任务前方法,在调用方法的线程中执行,并不一定是主线程
  • doInBackground 线程池中执行方法,异步执行任务
  • onPostExecute 结果回传方法;只有构造器传入handler不为主looper的handler对象,才会处理
  • onPreExecute 执行取消方法;只有构造器传入handler不为主looper的handler对象,才会处理
  • onProgressUpdate 需要用户主动在异步任务执行中,也就是doInBackground方法中,调用publishProgress,才会回调;只有构造器传入handler不为主looper的handler对象,才会处理
  1. 由于在主线程获取回调结果,而用户在主线程并不一定停留很久,所以,不适合执行很耗时的任务,不然,任务执行就没有意义了;如果这是你需要的意义也可以这么用
  2. 由于gc的原因,AsyncTask对象被线程池持有,那么AsyncTask持有的对象也不可被回收,除非任务运行完毕;所以实现AsyncTask的类不适合作为android 四大组件的内部类
  3. AsyncTask执行异步任务只能执行一次
  4. AsyncTask,中还有一些其它辅助小功能,比如获取主线程handler,直接执行线程
  5. AsyncTask中的线程池是进程中公有的,一个界面多个异步肯定会相互阻塞的

技术变化都很快,但基础技术、理论知识永远都是那些;作者希望在余后的生活中,对常用技术点进行基础知识分享;如果你觉得文章写的不错,请给与关注和点赞;如果文章存在错误,也请多多指教!