AsyncTask源码分析

本文详细解析了AsyncTask的工作原理,包括其定义、使用方法、内部机制及注意事项等,并通过实例展示了如何利用AsyncTask实现异步任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

分析完handler的机制之后,进阶我们分析一下AsycTask的常规操作,以及实现的源码,我们可以从一下几个方面去分析

1.什么是AsyncTask?
2.AsyncTask的使用方法
3.AsyncTask内部原理
4.AsyncTask的注意事项

什么是AsycTask?

我们可以用一句话进行总结:
AsycTask本质就是封装了线程池和handler的异步框架。

AsyncTask的使用方法

我们都知道AsyncTask是一个抽象类,我们使用它必须使用子类去继承它。AsyncTask有三个泛型参数,其代表的含义:
1. Params
在执行AsyncTask中的execute(..params)方法传入的参数,可用于在后台任务中使用。)
2. Progress
后台执行任务,如果在界面要显示进度,可使用此参数作为进度单位
3.Result
当任务完成之后,如果需要结果,则该泛型参数是对于返回值的类型

代码实例:

   public class Task extends AsyncTask<Void, Integer, String>{

        //运行在主线程中,在后台任务执行开始前调用,可以在此显示一个进度框,dialog
        @Override
        protected void onPreExecute() {
            progressDialog.show();
        }

        //运行在子线程中,我们可以在这里处理耗时操作,其中的返回值就是我们需要得到的结果类型
        @Override
        protected String doInBackground(Void... voids) {
            try {
                while (true) {
                    int downloadPercent = doDownload();
                    publishProgress(downloadPercent);
                    if (downloadPercent >= 100) {
                        break;
                    }
                }
            } catch (Exception e) {
                return false;
            }
            return true;
        }
        /*当后台调用了publishProgress()之后,这个方法就会调用,方法传递的参数就是后台传递过来的
            我们可在这方法处理进度条更新的操作
        */
        @Override
        protected void onProgressUpdate(Integer... values) {
            progressDialog.setMessage("当前下载进度:" + values[0] + "%");
        }

        /**
         * 当后台return语句返回的结果时,该方法会被调用,运行在ui线程中,可进行更新页面,显示数据的作用,以及
         * 关闭对话框
         * @param aVoid
         */
        @Override
        protected void onPostExecute(String aVoid) {
            progressDialog.dismiss();
            if (result) {
                Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
            }
        }
    }
AsyncTask内部原理

首先执行AsyncTask其子类必须实例化对象,我们可查看AsyncTask的构造方法.

 public AsyncTask() {
        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);
                }
            }
        };
    }

并没有进行逻辑性处理,只是初始化两个变量mWorker和mFuture,初始化mFuture的时候,将mWorker作为参数传入。mWorker是一个Callable对象,mFuture是一个FutureTask对象。这两个变量存在内存中。

接着如果我们执行AsyncTask,需要调用excute()的方法,我们可查询该方法:

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

该方法就执行了executeOnExecutor方法,我们可查询该方法:

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

该方法调用了onPreExecute()方法,因此证明了onPreExecute()方法会第一个得到执行。我们继续看下面Executor调用了execute()方法,接着我们可以去查Executor:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();  
……  
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;  

可以看到,这里先new出了一个SERIAL_EXECUTOR常量,然后将sDefaultExecutor的值赋值为这个常量,也就是说明,刚才在executeOnExecutor()方法中调用的execute()方法,其实也就是调用的SerialExecutor类中的execute()方法。那么我们自然要去看看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);  
        }  
    }  
}  

我们可以看到该类中有一个同步的方法execute(Runnable r)方法,其中实现了run()方法,run方法里面又执行了这个方法的参数Runnable的run方法(),这个Runnable也就是mFuture,接着我们可以查看一下FutureTask中的run():

 public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

该方法调用了callback的call方法,我们在前面可了解到,mFuture中传入的Callback的参数:

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

即此方法会被调用,我们终于找到了doInBackground(mParams),该方法运行在线程中,其finally执行了postResult(result):

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

我们熟悉handler就可以清楚明白了,message.sendToTarget()发送给handler:

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

handler进行接收执行 result.mTask.finish(result.mData[0]):

  private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

可以看到,如果当前任务被取消掉了,就会调用onCancelled()方法,如果没有被取消,则调用onPostExecute()方法,这样当前任务的执行就全部结束了。

我们注意到handler中还有一种消息类型MESSAGE_POST_PROGRESS,我们可在源码搜索到:

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

所以我们在doInBackground()方法中调用publishProgress()方法才可以从子线程切换到UI线程,从而完成对UI元素的更新操作。相信看完之后也非常清楚,其实AsyncTask只是对handler以及线程进行了封装而已。

AsyncTask的注意事项

关于AsyncTask的并行和串行问题,在不同的API下是有不同的。在Android1.6之前,AsyncTask是串行执行任务的;到了Android1.6时,开始采用线程池来并行执行任务;在Android3.0之后的版本中,AsyncTask又开始用一个线程串行执行任务。虽然Android3.0之后采用串行方式执行任务,但我们可以通过AsyncTask的executeOnExecutor(exe,params),自定义一个线程池来并行执行任务。
AsyncTask只能在主线程中创建以及使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值