Android Asynctask

本文详细介绍了Android中的AsyncTask类,包括其工作原理、使用方法及注意事项。AsyncTask是一种轻量级的后台任务处理机制,适用于执行简短的后台操作并将结果发布到UI线程。

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

简介

Android的UI工具包不是线程安全工具包,你不能通过工作线程操纵UI,而只能通过UI线程来操作用户界面,单线程模式必须遵守两条规则:

  1. 不要阻塞UI线程

  2. 不要在UI线程之外访问android的UI工具包

Asynctask可以恰当和容易的使用UI线程.这个类允许执行后台操作然后发布结果到UI线程而不需要处理线程和handler.

Asynctask被用作线程和handler的一个辅助类,不构成通用的线程框架.理论上它适合简短的操作(最多几秒),如果你需要让线程跑很长一段时间,你最好去使用java.util.concurrent包中提供的Executor,ThreadPoolExecutor和Futuretask.

Asynctask有3个泛型参数(Params,Progress,Result),4个执行步骤(onPreExecute,doInBackground,onProgressUpdate和onPostExecute).

Asynctask 相比 thread 和handler 更加轻量级一点。


使用

首先继承Asynctask<Params,Progress,Result> 类 ,并至少实现doInBackground(..)

范型参数说明:

Params:后台任务的输入参数,比如http请求的目标url

Progress:后台任务执行的进度

Result:后台任务返回的结果,比如Api调用返回的json数据


方法:

onPreExecute(), UI线程调用,在后台任务执行前调用,可以做一些准备工作,可以不实现。

doInBackground(Params…),工作线程执行,耗时的任务写在这里,必须实现。在这个方法里可以调用publishProgress方法来更新后台任务的实时进度,计算返回的结果将被传递给onPostExecute方法.

onProgressUpdate(Progress…),UI线程执行,在publishProgress方法(工作线程中)被调用后,UI线程调用它来显示任务的进度,如在进度条上显示,或textView上显示百分比。

onPostExecute(Result),UI线程调用,doInBackground()执行完成后被调用,后台任务执行的结果传递到这里当做参数。

onCancelled(),UI线程调用,有两个,有参数(doInBackground返回的数据)或无参数,


返回

主动调用asynctask的cancel方法,他会执行完doInBackground方法,然后执行onCancelled方法,不执行onPostExecute方法了。(为了尽快取消一个任务,在doInBackground方法中“定期检查”isCancelled()是否为true ,若为true 直接返回。比如在一个循环中)


注意事项

  1. asynctask一个实例只能execute一次。(asynctask有个状态变量,Status(FINISHED,PENDING,RUNNING))

  2. Asynctask类必须在UI线程加载,这时自动完成的.实例必须在UI线程创建,exxcute必须在UI线程调用.

  3. 不要手动调用onPreExecute(), onPostExecute(Result), doInBackground(Params…), onProgressUpdate(Progress…)方法.

  4. 有参数的onCancelled直接调了无参数的那个函数。

    protected void onCancelled(Result result) {
            onCancelled();
        }

Memory observability(观察内存)

Asynctask保证所有的回调方法的调用都是同步的,所以以下操作在没有明确同步情况下是安全的.

  • 在构造函数或onPreExecute()中设置成员变量,然后在doInBackground()使用.

  • 在doInBackground()中设置成员变量,然后在onProgressUpdate()和onPostExecute()中使用.


执行方式(并行还是串行)

当第一次被提出,Asynctask是在一个单独后台线程串行执行的.从Android.1.6开始,变成了一个允许多任务并行执行的线程池.从Android.3.0开始,为了避免并行执行引发的常见应用程序错误,任务在一个单独线程执行.

如果你想并行执行,你可以调用executeOnExecutor() 利用参数 THREAD_POOL_EXECUTOR.这个方法返回一个本身的一个引用.你也可以自己定义线程池.

public static ExecutorService exec = Executors.newFixedThreadPool(10);

并行执行可能导致修改顺序出错(写入文件),导致数据丢失和稳定性问题.所以最好是串行执行,无论android版本,你可以和 SERIAL_EXECUTOR 一起使用.


源码解析

从执行起点开始,execute方法:

//使用默认执行器 SERIAL_EXECUTOR
@MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

//这个方法设置执行器.
@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  继承了callable接口的抽象类
        mWorker.mParams = params;

        exec.execute(mFuture); //futuretask类型

        return this;
    }


    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
            Params[] mParams;
    }

    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   //在mworker的call方法执行完做的事情
           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);
               }
           }
       };
   }

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

    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; //携带运算结果和asynctask对象的一个对象.
            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;
            }
        }
    }

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

    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

使用线程执行runnable之后无法获得结果,使用callable加future可以传回运算结果(先执行call方法,调用futuretask的get()方法可以获得结果,会阻塞线程到得到结果). futuretask继承runnableFuture接口.

execute(mfuture) 会先执行它里面的callable对象,也就是继承了callable的workerRunnable的call方法,里面会执行doInBackground方法并获得结果,然后 postResult(result)获取handler发送消息,what变量为MESSAGE_POST_RESULT,根据what变量来采取不同的操作,最后还有一个finish方法.


参考资料

官方Asynctask文档

Asynctask源码解析

Android 异步消息处理机制 深入理解Looper Handler Message 的关系

Java线程:Callable和Future

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值