Android的AsyncTask异步任务浅析

作者: YuanchaoLi | 来源:发表于2019-03-27 08:24 被阅读10次

    Android的AsyncTask异步任务浅析

    实现原理

    内部封装了2个线程池+1个Handler(InternalHandler),1个线程池SerialExecutor任务排队,一个线程池THREAD_POOL_EXECUTOR执行任务。

    常用重写的方法

    • onPreExecute:运行在主线程中,可做UI更新,显示进度条通知等。
    • doInBackground:在子线程执行任务,接收的参数类型为AsyncTask第一个泛型,返回给onPostExecute的参数类型为AsyncTask第三个泛型。
    • onProgressUpdate:运行在主线程中,doInBackground中调用publishProgress方法后即可回调到该方法中,用于UI进度更新。接收的参数类型为AsyncTask第二个泛型。
    • onPostExecute:运行在主线程中,doInBackground任务执行完毕后,就会回调到该方法中。
    • onCancelled:调用AsyncTask的cancel方法时,会回调到该方法中,内部调用Thread的interrupt方法,告诉线程池要取消任务,Thread在合适时机取消任务。
    public class MyTask extends AsyncTask<String, Double, Float> {
    
        @Override // 子线程执行任务
        protected Float doInBackground(String... strings) {
            publishProgress(5D);
            return 1f;
        }
    
        @Override // 准备执行doInBackground任务时回调
        protected void onPreExecute() {
            super.onPreExecute();
        }
    
        @Override // doInBackground任务执行结束后回调,接收的参数为doInBackground返回的值
        protected void onPostExecute(Float aFloat) {
            super.onPostExecute(aFloat);
        }
    
        @Override // doInBackground调用publishProgress会回调到该方法中
        protected void onProgressUpdate(Double... values) {
            super.onProgressUpdate(values);
        }
    
        @Override // 调用AsyncTask的任务关闭后回调
        protected void onCancelled() {
            super.onCancelled();
        }
    }
    

    注意事项

    1. Android4.1之前,AsyncTask类必须在主线程中加载。Android4.1之后,没有了这个要求,ActivityThread的main方法中自动加载了AsyncTask。
    2. AsyncTask对象要在主线程创建,创建时,AsyncTask构造方法中,会拿到当前线程的Looper,传给new的Handler实例,以保证Handler是在主线程中。
    public AsyncTask(@Nullable Looper callbackLooper) {
            // 创建AsyncTask对象时,若不传外部的Handler实例,会走到这个构造中
            // 拿到当前线程的Looper,传给new的Handler,则Handler在当前创建AsyncTask对象的线程中
            // 因此,若要保证Handler执行环境在主线程,必须要在主线程中创建AsyncTask对象
            mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
                ? getMainHandler()
                : new Handler(callbackLooper);
                
            ......省略无关代码
        }
    
    1. AsyncTask对象的execute方法必须在主线程中调用。execute方法有@MainThread注解。
    2. Android3.0之前AsyncTask调execute方法是并行执行任务,3.0之后增加了SerialExecutor线程池,默认选择该线程池串行执行任务,若想并行执行,则直接调executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)方法即可。
    MyTask myTask = new MyTask();
    // 默认在SerialExecutor线程池中串行执行
    myTask.execute("1");
    // 并行执行
    myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "1");
    
    1. 一个AsyncTask对象,只能执行一次execute方法,第二次执行就会抛异常。
    @MainThread // 主线程中执行的方法,默认选择SerialExecutor线程池串行执行任务
    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) {
        // 一个AsyncTask对象,若多次执行execute,走到这里,会判断任务在执行中或已结束时,都将抛异常
        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;
    }
    
    1. 内存泄漏问题。采用静态的AsyncTask继承类,若要引用外部,采用弱引用。
    2. 使用多个异步操作并需要进行UI变更时,用AsyncTask会很复杂,替换Handler会更灵活。

    相关文章

      网友评论

        本文标题:Android的AsyncTask异步任务浅析

        本文链接:https://www.haomeiwen.com/subject/hvkavqtx.html