基础六: Android P 版本中 AsyncTask详解

基础一:ContextMenu,Option Menu和PopupMenu
基础二:为什么Button,ImageButton有焦点,textview,imageview没有焦点
基础三:一些重要方法的解释
基础四:Handler详解
基础五:不在Application类里面如何对全部activity生命周期监听

  AsyncTask故名思议这是一个异步任务类,这个类在源码设计上运用了很多java特性,如泛型,带返回结果的线程,线程池等等,深入理解AsyncTask源码不仅对我们理解AsyncTask有帮助,也对我们学习java高级知识点有所帮助,这里涉及到的有 泛型,feturetask等

  首先我来纠个错,在很多网页中或者开发书籍说AsyncTask类的实例需要在主线程当中,同时execute方法需要在主线程当中执行?这是真的吗?

  答案是否; 首先我们从源码开始分析

  在Android 20开始,ActivityThread的main方法变会调用AsyncTask的init方法去迫使创建主线程的Handler,最新Android 28虽然在ActivityThread的main方法中不再调用AsyncTask的init方法,同时AsyncTask也移除了init方法,但是在AsyncTask加载的时候,变会通过静态方法getMainHandler来完成创建主线程Handler;

    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

  不管Android 20还是Android 28,通过创建主线程的Handler来收发消息,这样AsyncTask的一些重写的方法变可以在主线程当中执行了

那为什么网络上会有那么多主线程创建AsyncTask实例的文章尼,细想下肯定是AsyncTask的某个重写方法不在主线程当中被回调,从而导致UI刷新crash,

为了保证版本的兼容性,我们还是在 主线程创建AsyncTask的实例吧


  一个简单的继承自AsyncTask的类

private class MyAsnycTask extends AsyncTask<String, Object, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }

        @Override
        protected void onProgressUpdate(Object... values) {
            super.onProgressUpdate(values);
        }

        @Override
        protected void onCancelled(String s) {
            super.onCancelled(s);
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
        }

        @Override
        protected String doInBackground(String... strings) {
            return null;
        }
    }
  1. AsyncTask是一个采用了泛型方式的抽象类:abstract class AsyncTask<Params, Progress, Result>,其中Params表示传递的参数的类型,Progress表示后台执行的进度,Result表示后台任务返回结果类型;
  2. onPreExecute方法在主线程当中执行,一般用于做一些准备工作,优先于doInBackground方法
  3. doInBackground方法在子线程中执行,子线程是运行在线程池中的
  4. onProgressUpdate方法运行在主线程中,这是因为它是通过创建的主线程Handler收发MESSAGE_POST_PROGRESS消息来执行onProgressUpdate,该方法作用是后台任务进度发生变化会被调用
  5. onPostExecute方法运行在主线程中,这是因为它是通过创建的主线程Handler收发MESSAGE_POST_RESULT消息来执行onPostExecute
  6. onCancelled()和onCancelled(Result result)都是在主线程当中执行,onCancelled(Result result)内部也是调用onCancelled()来完成的,onCancelled()方法会在客户端调用cancel(boolean mayInterruptIfRunning)或者doInBackground执行完毕之后被触发;
    6.1 其中cancel(boolean)的作用是尝试取消一个正在执行的任务;当一个任务没有开始运行的时候,调用cancel是会成功的;可是如果一个任务已经开始了,那么则需要根据mayInterruptIfRunning来看执行此任务的线程是否应该被中断来试图阻止任务,其中如果mayInterruptIfRunning为true表示此任务应该被打断,false表示不被打断,将被运行执行完成

  AsyncTask源码分析

  1. 构造AsyncTask
    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        this((Looper) null);
    }

注释要求我们在UI线程创建这个实例… …

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

在构造AsyncTask的时候主要创建了三个属性
1)mHandler: 主线程Handler,用于发送消息给主线程
2)WorkerRunnable类型的mWorker:一个抽象的泛型类,实现了Callable接口,主要目的就是后台执行任务即调用doInBackground方法,并通过mHandler发送MESSAGE_POST_RESULT消息在UI线程完成onPostExecute操作,onPostExecute的参数即doInBackground操作返回的值
3)FutureTask类型的mFuture,因为WorkerRunnable实现了Callable接口,那必然需要一个FutureTask类来调用mWork做后台任务,完成后会调用FutureTask的done方法,done方法也很简单,他完成的是通过mHandler发送MESSAGE_POST_RESULT消息通知UI线程完成onPostExecute操作

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

其中sDefaultExecutor为一个实现了Executor接口的串行线程池

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

第15行,当一个任务开始调用execute方法之后,就会被标注为Status.RUNNING状态
第5行,当一个正在执行的任务,如果多次调用execute方法,就会抛出new IllegalStateException(“Cannot execute task:” + " the task is already running.");的异常
第17行,在主线程调用onPreExecute方法,完成一些初始化工作
第19行,将传递过来的参数paramsm赋值给mWorker.mParams,以方便mWorker完成后台任务
第20行,通过FutureTask的方式开始执行这个mWorker;mWorker完成之后会调用FutureTask的done方法

  1. AsyncTask更新进度操作
    在后台执行任务doInBackground中,我们可以计算当前下载进度然后通过调用publishProgress方法完成进度更新
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

其通过UI线程的handler发送MESSAGE_POST_PROGRESS消息,

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

使得onProgressUpdate方法被调用


   那我们如何并行执行任务?

在AsyncTask内部其实还定义了一个线程池:threadPoolExecutor

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

我们利用这个线程池就能完成任务的并行操作,简单的代码如下

 MyAsnycTask myAsnycTask = new MyAsnycTask();
myAsnycTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"hello");

这里虽然可以异步执行任务,但是因为他也是通过executeOnExecutor方法完成,所以他一样遵循如下原则
1):一个AsnycTask实例只能执行一次,如果多次执行会抛出IllegalStateException异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值