Android AsyncTask内部原理

作者: 一个不熬夜的孩子 | 来源:发表于2016-12-27 23:47 被阅读173次

    Android AsyncTask内部原理

    @(Android)

    [toc]

    小笔记

    基本使用

    /**
     * 在主线程中调用,可以做一些初始化的操作,但是不要在这里做耗时操作
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    
    /**
     * 在子线程中调用,耗时操作全部在这里完成。
     * 如果需要更新进度可以调用 publishProgress(Progress... values)
     */
    @Override
    protected Object doInBackground(Object[] params) {
        return null;
    }
    
    /**
      * 在主线程中调用,显示子线程进度的回调函数
      * @param values
      */
     @Override
     protected void onProgressUpdate(Object[] values) {
         super.onProgressUpdate(values);
     }
    
    /**
      * 在主线程中调用,传入的传输是在doInBackground中返回的值
      * @param o
      */
     @Override
     protected void onPostExecute(Object o) {
         super.onPostExecute(o);
    }
    
    /**
     * AsyncTask被取消的时候会回调
     * 参数是从哪里传过来的呢。后面有解释
     */
    @Override
    protected void onCancelled(Object o) {
        super.onCancelled(o);
        System.out.println(o instanceof Bitmap);
        if (o instanceof Bitmap) {
            image_view.setImageBitmap((Bitmap) o);
        }
    }
    /**
     * AsyncTask被取消的时候会回调
     */
    @Override
    protected void onCancelled() {
        super.onCancelled();
        System.out.println("MyAsyncTask ========== onCancelled");
    }
    

    了解了基本的使用方法之后,简单的实现一个加载图片的方法吧

    package com.example.wen.asynctask;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.ImageView;
    
    import java.io.IOException;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView image_view;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            image_view = (ImageView) findViewById(R.id.image_view);
            new MyAsyncTask().execute();
        }
    
        class MyAsyncTask extends AsyncTask {
    
            /**
             * 在主线程中调用,可以做一些初始化的操作,但是不要在这里做耗时操作
             */
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }
    
            /**
             * 在子线程中调用,耗时操作全部在这里完成。
             * 如果需要更新进度可以调用 publishProgress(Progress... values)
             */
            @Override
            protected Object doInBackground(Object[] params) {
    
                Bitmap bitmap = null;
    
                try {
                    URL url = new URL("https://www.baidu.com/img/bd_logo1.png");
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    
                    bitmap = BitmapFactory.decodeStream(connection.getInputStream());
    
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
                return bitmap;
            }
    
            /**
             * 在主线程中调用,传入的传输是在doInBackground中返回的值
             * @param o
             */
            @Override
            protected void onPostExecute(Object o) {
                super.onPostExecute(o);
    
                if (o instanceof Bitmap) {
                    image_view.setImageBitmap((Bitmap) o);
                }
            }
    
            /**
             * 在主线程中调用,显示子线程进度的回调函数
             * @param values
             */
            @Override
            protected void onProgressUpdate(Object[] values) {
                super.onProgressUpdate(values);
            }
    
            /**
             * AsyncTask被取消的时候会回调
             */
            @Override
            protected void onCancelled(Object o) {
                super.onCancelled(o);
                System.out.println(o instanceof Bitmap);
                if (o instanceof Bitmap) {
                    image_view.setImageBitmap((Bitmap) o);
                }
            }
            /**
             * AsyncTask被取消的时候会回调
             */
            @Override
            protected void onCancelled() {
                super.onCancelled();
                System.out.println("MyAsyncTask ========== onCancelled");
            }
        }
    }
    

    内部实现原理

    1. 在主线程中调用execute(Params... params)方法或者是指定的线程池的executeOnExecutor(Executor exec,Params... params)
     @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.mParams = params;
        exec.execute(mFuture);
    
        return this;
    }
    

    从上面的代码中看到两点:

    1. onPreExecute()方法在主线程中调用的
    2. 另外,在执行exec.execute(mFuture);的时候,会先判断mStatus的状态。所以每一个AsyncTask对象都只能调用execute()方法一次。看一下mStatues的定义:
    private volatile Status mStatus = Status.PENDING;
    
    public enum Status {
        /**
         * Indicates that the task has not been executed yet.
         */
        PENDING,
        /**
         * Indicates that the task is running.
         */
        RUNNING,
        /**
         * Indicates that {@link AsyncTask#onPostExecute} has finished.
         */
        FINISHED,【
    }
    

    从定义中看到mStatus是用volatile关键字修饰的。volatile的作用是保证操作的可见性,即修改之后其他能马上读取修改后的值。详情看Java 并发编程
      那为什么需要用一个volatile关键字修饰呢。现在有这么一个场景,一个AsyncTask对象已经快执行完后台任务了,准备修改状态Statue.FINISH,但是这个时候,主线程保留了这个AsyncTask对象,并且调用了execute()方法,这个时候就会导致一个AsyncTask被调用了两次。
      而一个AsyncTask不允许执行两次的原因是考虑到了线程安全的问题,如果一个对象被执行了两次,那么就需要考虑自己定义的成员变量的线程安全的问题了。所以直接在new一个出来比执行两次的方式更加方便。

    当判断是第一次调用的时候,后面就会调用到exec.execute(mFuture);方法。线程池中的exec.execute()需要一个Runnable的对象,所以让我们看看mFuture的定义吧:

    private final FutureTask<Result> mFuture;
    

    我们发现他是一个FutureTask对象。FutrueTask对象需要实现一个方法:

     /**
      * Protected method invoked when this task transitions to state
      * {@code isDone} (whether normally or via cancellation). The
      * default implementation does nothing.  Subclasses may override
      * this method to invoke completion callbacks or perform
      * bookkeeping. Note that you can query status inside the
      * implementation of this method to determine whether this task
      * has been cancelled.
      */
    protected void done() { }
    

    并且在FutureTask的构造方法中,需要传一个Callable对象,那么Callable又是一个什么东西呢。简单来说,Callable是一个有返回值的Runnable。所以FutureTask在后台运行的代码就是Callable中的call()的方法。具体来看看在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
        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是一个实现了Callable的类,并且用一个变量保存了在执行AsyncTask时传入的参数

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

    上面的代码的大概意思就是在一个子线程中调用了我们实现的doInBackground()方法。在FutureTask中的done()方法中有一个get()方法,作用就是获取doInBackground()返回的数据。然后将返回的数据传到postResult方法中:

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

    在这里可以看到AsyncTask的内部是通过Handler来实现的。这里还有一个AsyncTaskResult

     private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;
    
        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }
    
    private void finish(Result result) {
     if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
    
    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;
            }
        }
    }
    

    因为在finish()方法中需要判断Task是否被取消,而Status是对象内部的成员变量,所以需要保留一个AsyncTask对象和在子线程中返回的数据。

    当执行完finish()方法之后,基本AsyncTask的内部原理都讲完了。耶!!

    相关文章

      网友评论

        本文标题:Android AsyncTask内部原理

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