美文网首页
4.AsyncTask使用,原理

4.AsyncTask使用,原理

作者: Varmin | 来源:发表于2017-06-03 22:32 被阅读0次

    资料

    概述:

    Android中,实现异步有两种方式,Handler和AsyncTask。
    使用Handler+Thread时,每次执行耗时操作都需要创建新的线程进行处理,代码比较臃肿,性能开销也会较大。
    使用AsyncTask,内部是封装好的Handler+Thread,并且使用了线程池,有效的优化了性能。

    "AsyncTask并不适合进行特别耗时的后台任务,对特别耗时的任务,建议使用线程池。--开发艺术探索上所写,但是还并未理解"
    可能是因为:多个任务时特别耗时的任务会影响后面的任务迟迟不能执行。用线程池并发的话,就没这样的问题了。

    原理:

    轻量级的异步任务类,在线程池中串行执行任务,通过Handler把进度和执行结果发送到主线程,更新UI。

    简单使用:

     MyAsyncTask mAsyncTask = new MyAsyncTask();
    mAsyncTask.execute();//下面后台任务参数为Void类型,所以不填参数。
     
    /**
    *AsyncTask<Void, Integer, Boolean>:泛型,可以为任意类型。
    *分别为:后台任务执行的参数,更新进度的参数,任务执行完成的结果
    */
    public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{
            private ProgressDialog mProgress;
            private int currentProgress;
            //任务开始前的准备操作,可以做些UI的准备或初始化。
            //多个任务时,无论是否等待,execute()的时候就在主线程调用
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                mProgress.setMax(100);
                mProgress.setMessage("下载进度");
                mProgress.show();
            }
    
            //线程池中执行任务
            @Override
            protected Boolean doInBackground(Void... params) {
                while (currentProgress <= 100) {
                    //不能跟新UI
                    //mProgress.setProgress(currentProgress);
                    //想更新进度的话,主动调用该方法,会通过handler给onProgressUpdate方法。
                    publishProgress(currentProgress);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                       return false;
                    }
                    currentProgress++;
                }
                return true;
            }
    
            //publishProgress通过handler调用,主线程
            @Override
            protected void onProgressUpdate(Integer... values) {
                mProgress.setMessage("下载进度:"+values[0]);
            }
    
            //执行完成后的结果。
            @Override
            protected void onPostExecute(Boolean aBoolean) {
                super.onPostExecute(aBoolean);
                if (aBoolean) {
                    mProgress.setMessage("下载完成");
                }else {
                    mProgress.setMessage("下载出错");
                }
    
                    mProgress.cancel();
            }
            
            //中断任务时,调用该方法。但并不一定会马上中断。
            @Override
            protected void onCancelled() {
                super.onCancelled();
            }
        }
    

    原理,源码分析:

    按照调用方法,一步一步的分析。

    • 构造函数入手:
    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跟结果通知有关。这里看不懂正常,也不要每步都要求详细清楚,往下看。

    • 调用mAsyncTask.execute()方法:
    方法1:    
        public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return executeOnExecutor(sDefaultExecutor, params);
        }
    
    方法2:    
        public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
                Params... params) {
            //如果状态为正在运行或者已经结束,报错。说明,只能调用一次mAsyncTask.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;//改变状态
    
            //看好了哈,在此处调用。此时还是在主线程中哦,所以可以操作UI。
            onPreExecute();
    
            //构造方法中的一个实例,把执行后台任务的参数给了它。
            mWorker.mParams = params;
            //该exec是方法1中的sDefaultExecutor,看下面代码.
            exec.execute(mFuture);
    
            return this;
        }
        
    

    1.只能执行一次mAsyncTask.execute()方法。
    2.主线程调用onPreExecute()
    3.更改状态,赋值。
    4.调用线程池有关方法执行。sDefaultExecutor.execute(mFuture)
    继续往下看,调用的方法:

        private static volatile Executor sDefaultExecutor = new SerialExecutor();
        //Executor?线程池类?
        private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            Runnable mActive;
            //mFuture参数,也即是构造方法中的实例
            public synchronized void execute(final Runnable r) {
                //封装成一个Runnable,放到队列的最后。
    语句1:        mTasks.offer(new Runnable() {
                    public void run() {
                        try {
                        //mFuture的run方法,只是调用方法,run并没有开新线程
    语句5:              r.run();
                        } finally {
    语句6:              scheduleNext();
                        }
                    }
                });
                //第一次执行时
                if (mActive == null) {
    语句2:             scheduleNext();
                }
            }
    
            protected synchronized void scheduleNext() {
                //取出队列中第一个封装好的Runnable
    语句3:     if ((mActive = mTasks.poll()) != null) {
                    //THREAD_POOL_EXECUTOR是线程池
    语句4:        THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }
        }
    

    执行步骤,按语句顺序:将mFuture的run方法封装成Runnable对象放入队列最后--->第一次执行时,取出Runnable并到线程池中执行--->执行完以后,再取,再去执行。以此类推...
    需要注意:封装好的Runnable在线程池中会开新的线程。mFuture的run只是一个方法,也就是说此时run中的代码已经在子线程了。
    上面整个过程都是在放入/取出Runnable,最主要的是执行的mFuture的run方法。

    //FutureTask类,mFuture的run方法
    public void run() {
            if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
                return;
            try {
    语句1:    Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran;
                    try {
    语句2:             result = c.call();
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;
                        ran = false;
                        setException(ex);
                    }
                    if (ran)
    语句3:             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);
            }
        }
    

    语句1中的callable是构造函数中初始化mFuture的用到的第一个实例mWorker啊。
    语句2执行了mWorker的call方法。
    语句3最后执行了mFuture的done方法。
    语句2,3执行的正好是构造时两个实例复写的方法:先执行call,再执行done。
    再回过头来看AsyncTask的构造方法:

        public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
    语句0           mTaskInvoked.set(true);
                    Result result = null;
                    try {
                        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        //noinspection unchecked
    语句1:             result = doInBackground(mParams);
                        Binder.flushPendingCommands();
                    } catch (Throwable tr) {
                        mCancelled.set(true);
                        throw tr;
                    } finally {
    语句2:            postResult(result);
                    }
                    return result;
                }
            };
    
            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                protected void done() {
                    try {
    语句3:           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);
                    }
                }
            };
        }
    
    

    语句1就是生成AsyncTask实例时复写的后台执行任务的方法:doInBackground() 在线程池中执行的。

        @WorkerThread
        protected abstract Result doInBackground(Params... params);
    

    语句2拿到后台任务执行后的result,通过mainHandler调用onPostExecute(result);

        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;
                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;
        }
        
        protected void onPostExecute(Result result) {
        }
    

    另外,语句3的 postResultIfNotInvoked(get()),如果满足条件,也会调用postResult通过handler....
    但是,正是因为语句0的设置,使其并不满足条件,所以不执行。(不太清楚wasTaskInvoked的作用)

        private void postResultIfNotInvoked(Result result) {
            final boolean wasTaskInvoked = mTaskInvoked.get();
            if (!wasTaskInvoked) {
                postResult(result);
            }
        }
    

    至此,关于调用mAsyncTask.execute()方法,上面的源码分析完了,先把任务放入队列最后,然后取出队列第一个,在线程池中调用了doInBackground,后通过主线程的handler调用onPostExecute(Result result);

    • publishProgress:该方法可以再doInbackGroud中给onProgressUpdate更新进度。上面分析的过程中,程序并不会自动调用该方法,需要用到的时候,我们自己调用就行了。
        protected final void publishProgress(Progress... values) {
            if (!isCancelled()) {
                getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                        new AsyncTaskResult<Progress>(this, values)).sendToTarget();
            }
        }
        
    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;
                }
            }
            
    protected void onProgressUpdate(Progress... values) {
        }
    

    至此,整个AsyncTask执行过程就分析完了。跨度太大,总结一下:
    1.onPreExecute()在mAsyncTask.execute(...params)执行的时候,马上执行,主线程。
    2.doInBackgroun在线程池中调用。子线程。
    3.得到结果后,通过主线程的handler发送消息,调用onPostExecute。主线程。
    4.手动调用publishProgress会通过主线程的handler调用onProgressUpdate。 主线程。

    相关文章

      网友评论

          本文标题:4.AsyncTask使用,原理

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