第十一章-Android线程和线程池(AsyncTask、HandlerThread、IntentService)

Android中的线程形态

本节将对Android中的线程形态做一个全面的介绍,除了传统的Thread以外,还包含了AsyncTask,HandlerThread以及IntentService,这三者的底层实现也是线程,但是他们具有特殊的表现形式,同时在使用上也各有优缺点,下面从源码的角度来分析AsyncTask的执行过程。

一、AsyncTask

AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler,通过AsyncTask我们更加方便的执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。

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

public abstract class AsyncTask<Params, Progress, Result> 

AsyncTask提供了4个核心方法,它们的含义如下所示。

  • onPreExecute()

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

  • doInBackground(Params… params)

在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress会调用onProgressUpdate方法。此外此方法需要返回计算结果给onPostExecute方法。

  • onProgressUpdate(Progress… values)

在主线程执行,当后台任务的执行进度发生改变时此方法会被调用。

  • onPostExecute(Result result)

在主线程中执行,在异步任务结束之后,此方法被调用,其中result参数是后台任务的返回值,即DoInBackground的返回值。

上面几个方法,onPreExecute先执行,接着是doInBackground,最后才是onPostExecute。除了上述四个方法以外,AsyncTask还提供了一个onCancelled()方法,它同样在主线程中执行,当异步任务被取消时,onCancelled就会被调用,这个时候onPostExecute就不会被调用。下面提供一个典型的示例(这个示例就是源码中的)

   class DownloadTask extends AsyncTask<URL,Integer,Long>{
   

        @Override
        protected Long doInBackground(URL... urls) {
   
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < totalSize; i++) {
   
                totalSize += DownLoad.downloadFile(urls[i]);
                publicProgress((int)((i / (float)count)*100));
                if(isCancelled()){
   
                    break;
                }
            }
            return totalSize;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
   
           setProgressPercent(values[0]);
        }

        @Override
        protected void onPostExecute(Long aLong) {
   
            showDialog(aLong);
        }
    }

AsyncTask在使用的过程中也有一些条件限制的,主要有如下几点:

  • 1、AsyncTask的类必须在主线程加载,也就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android4.1之后已经被系统自动完成了,在Android5.0的源码中,可以看到ActivityThread的main方法,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中加载这个条件了。
  • 2、AsyncTask的对象必须在主线程创建。
  • 3、execute方法必须在UI线程调用。
  • 4、不要再程序中直接使用onPreExecute、onPostExecute、DoInBackground和onProgressUpdate方法。
  • 5、一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会运行时异常。
  • 6、在Android1.6之前,AsyncTask是串行执行任务的,Android1.6之后开始采用线程池并行处理,但是从Android3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行任务。尽管如此,在Android3.0以及以后的版本中,我们也可以通过AsyncTask的executteOnExecutor方法来并行的执行任务。

二、AsyncTask的工作原理
为了分析AsyncTask的工作原理,我们从它的execute方法开始分析

	android.os.AsyncTask#execute
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
   
		//private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
        return executeOnExecutor(sDefaultExecutor, params);
    }

	android.os.AsyncTask#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.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值