线程形态之AsyncTask

 

线程分为主线程和子线程,主线程主要处理和界面有关的事情,而子线程往往用于执行耗时操作;

除了Thread,扮演线程角色的还有很多,如AsyncTask,IntentService,HandlerService,

AsyncTask底层用到的是线程池,而IntentService和HandlerService底层直接使用了线程。

AsyncTask封装了线程池和Handler,它主要是方便在主线程更新UI;

HandlerThread是一种具有消息循环的线程,它的内部可以使用Handler;

IntentService是一个服务,系统对其进行了封装,使其可以更方便的执行后台任务;IntentService内部采用了HandlerThread来执行任务,当任务执行完毕后,IntentService会自动退出。

IntentService更像是一个后台线程,但是它是一种服务,它不容易被系统杀死从而保证任务的执行;而如果是一个后台线程,由于这个时候进程中没有活动的四大组件,那么这个进程的优先级就会非常低,会很容易被系统杀死,这就是使用IntentService的优点。

 

AsyncTask:

好处:简化子线程中访问UI的过程;

AsyncTask是一个轻量级的异步任务类,它可以在线程中执行后台任务,然后把执行的进度和最终结果传递给主线程,并且在主线程上更新UI。

AsyncTask并不适合执行特别耗时的任务,对于特别耗时的任务来说,建议使用线程池。

AsyncTask是一个泛型类,它提供了Params,Progress和Result三个泛型参数,Params表示参数的类型,Progress表示后台任务的执行进度的类型,Result是后台任务的返回结果类型;如果AsyncTask确实不需要传递具体的参数,那么这三个泛型参数可以用Void来代替;

具体声明如下:

public abstract class AsyncTask<Params,Progress,Result>。

它有4个核心方法:

onPreExecute(),在主线程执行,在异步任务执行之前会被调用,一般可以用于做些准备工作;

doInBackground(Params... params),在线程池中执行,此方法用于执行后台任务,params表示输入的参数。此方法中可调用publishProgress方法来更新任务的进度,publishProgress会调用onProgressUpdate方法,另外,此方法需要返回结算结果给OnPostExcute方法;

onProgressUpdate(Progress... values),在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用;

onPostExecute(Result result),在主线程执行,在异步任务执行之后调用,其中result参数是后台任务的返回值,即doInBackground的返回值;

onCanceled(),在主线程中执行,当异步任务取消时,该方法会被调用,这个时候,onPostExecute不会被执行;

注意以下几点:

1.AsyncTask的类必须要在主线程中加载,即第一次访问AsyncTask必须发生在主线程中;

2.AsyncTask的对象必须要在主线程中去创建;

3.execute方法必须要在UI线程中执行;

其中1.2.3只在android2.3以后不作要求,后面会解释;

4.一个AsyncTask对象只能执行一次,即只能调用一次execute,否则会报异常;

5.通过AsyncTask的executeOnExecutor方法来并行的执行任务;

 

分析流程:

1.来看execute方法,他会调用到executeOnExecutor方法:

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;
    }

其中,extc是是一个串行的线程池,一个进程中的所有的AsyncTask全部在这个串行的线程池中排队,如下:

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

来看executeOnExecutor中的exec.execute(mFuture)这个方法,mFuture实在AsyncTask的构造函数中被定义的

来看AsyncTask的构造方法:

public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(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);
                }
            }
        };
    }

系统将AsyncTask的Params参数封装为FutureTask对象,FutureTask在这里充当了Runnable的作用;

exec.execute(mFuture):将Future对象插入到任务队列mTasks,这里的SerialExecutor线程池是被static修饰的,也就是该SerialExecutor被所有的AsyncTask共享的,所以,每个AsyncTask的Future对象都被插入到共享任务队列mTasks中,再进行判断此时是否有正在活动的AsyncTask任务,如果没有,即mActive == null,也就是任务队列中无内容,此时便会调用scheduleNext方法,立即执行该AsyncTask的请求;如果有此时有活动的AsyncTask任务正在执行的话,便等待上个AsyncTask执行完;当上个AsyncTask执行完,会调用scheduleNext方法执行下一个任务直到所有的任务被执行为止;

可以看出,在默认情况下,AsyncTask是串行执行的;

2.scheduleNext()方法:

THREAD_POOL_EXECUTOR.execute(mActive);

THREAD_POOL_EXECUTOR是真正的执行任务的线程池,如下

public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

这个线程池被static final修饰,即该线程池是被所有的AsyncTask子类共享的,所有的线程任务都在该线程池中被执行;

3.mFutureTask的run方法,会调用mWorker的call()方法,在该call方法里,先后调用了doInBackground和postResult方法;

4.postResult方法会使用到一个Handler,该Handler就是通过主线程的Looper创建的;

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

        @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;
            }
        }
    }

在android2.3以前,因为我们要将执行环境切换到主线程,这就要求该Handler对象必须要在主线程中创建,InternalHandler 是被static修饰的,静态成员会在加载类的时候被初始化,所以要求AsyncTask的类第一次使用时必须要在主线程中加载;但是在android2.3以后,InternalHandler使用的是主线程的looper,也就是说,AsyncTask可以在任意线程中使用

从以上分析我们可以看出,AsyncTask是串行执行,即前一个完成之后,才能进行下一个,也就变相的说明了,在AsyncTask中,不能执行太耗时的任务;

为了让AsyncTask可以并发的执行,我们需要替换线程池,将串行的线程池exec替换成THREAD_POOL_EXECUTOR,调用方法如下:

executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params);

当然我们也可以使用其他线程池来代替THREAD_POOL_EXECUTOR

替换了线程池之后,便可以并发执行的需求;

 

总结:

AsyncTask中有两个线程池(SerialExecutor 和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler);

其中SerialExecutor用于任务的排队,而THREAD_POOL_EXECUTOR用于真正的执行任务,InternalHandler用于将执行环境切换从线程池到主线程去执行;

 

转载于:https://my.oschina.net/u/3491256/blog/906224

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值