• Android异步任务处理框架AsyncTask源代码分析


    【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】

    引言

    在平时项目开发中难免会遇到异步耗时的任务(比方最常见的网络请求)。遇到这样的问题。我们能够自己通过Handler+Message+Thread/ThreadPool来构造一个异步耗时任务框架。当你下次项目中又遇到一个网络请求,你又不得不重写异步耗时任务处理框架。出于避免开发人员反复搬砖工作,Googleproject师给开发人员搭建了一个通用的异步耗时任务处理框架—-AsyncTask。

    AsyncTask简单介绍

    我把AsycnTask类称之为异步任务处理框架。为什么这么说?由于其内部通过Handler+Message+ThreadPool技术构建了一个异步耗时任务处理框架。所谓框架,无非就是封装复杂的逻辑操作,留给开发人员少数接口或者方法来进行数据操作。AsyncTask类也一样。目的是让开发人员非常方便easy的在UI线程中处理一些异步耗时任务。

    AsyncTask类中将异步耗时任务处理放在ThreadPool线程池中处理,然后将处理结果通过Handler发送消息更新进度和结果,开发人员仅仅须要实现和重写AsyncTask类中的几个方法就可以获得当前异步任务处理的进度和结果。

    AsyncTask使用

    由于AsyncTask是一个抽象类,所以开发人员假设想使用AsyncTask类的话必须让子类去继承它。

    子类至少重写AsyncTask类中的 doInBackground方法,一般我们也会重写onPostExecute方法去获取异步任务处理结果。在使用AsyncTask类时。我们知道须要准备3个泛型參数各自是:

    • Params:异步任务运行时须要的參数类型
    • Progress:异步任务运行过程中进度更新类型
    • Result:异步任务运行结束返回的结果类型

    当你在使用AsyncTask无需对应的參数时能够将对应參数设置为 Void类型。

    AsyncTask使用的步骤顺序可分为例如以下:

    1. onPreExecute:该方法由系统在UI线程中调用,异步任务运行之前调用。做一些准备工作,比方初始化进度条。无需用户自己去调用,用户仅仅需重写该方法就可以。当然用户也能够不重写该方法。
    2. doInBackground:该方法由系统运行于后台线程中。当onPreExecute方法调用之后就调用该方法。全部异步耗时的任务都是在该方法中实现,相同用户无需自己去调用,用户仅仅需重写该方法就可以。且必须重写该方法。

    3. publishProgress:该方法在doInBackground方法中调用。用于公布当前异步任务运行的进度到UI线程中,该方法须要用户自己在onInBackground中调用。
    4. onProgressUpdate:该方法由系统在UI线程中调用。用于更新当前异步任务运行的进度。进而更新UI操作,该方法也无需用户自己调用,用户仅仅需重写该方法就可以。想要在UI线程中获得进度信息的前提是在doInBackground方法中调用了publishProgress方法。
    5. onPostExecute:该方法由系统在UI线程中调用,用于异步任务运行完毕之后获取后台线程运行的结果。该方法相同无需用户自己调用,仅仅需重写该方法就可以。

    上面的解释可能会有点抽象,如今我们拿一个样例来说明AsyncTask的使用。

    public class MainActivity extends AppCompatActivity {
    
        private ProgressBar progressBar;
        private TextView value;
        private TextView result;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            result = (TextView) findViewById(R.id.result);
        }
    
        //启动一个任务
        public void startTask(View view) {
            String s1 = "task1";
            String s2 = "task2";
            String s3 = "task3";
            String s4 = "task4";
            String s5 = "task3";
            String s6 = "task3";
            String s7 = "task3";
            String s8 = "task3";
            new DownloadFilesTask().execute(s1, s2, s3, s4, s5, s6, s7, s8);
        }
    
        private class DownloadFilesTask extends AsyncTask<String, Integer, Long> {
    
            //该方法运行与后台线程中,全部异步耗时的任务都在此处操作   
            @Override
            protected Long doInBackground(String... urls) {
                int count = urls.length;
                long totalSize = 0;
                for (int i = 0; i < count; i++) {
                    try {
                        Thread.sleep(1 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    totalSize += 800;
                    //公布进度信息到UI线程中
                    publishProgress((int) ((i / (float) (count - 1)) * 100));
                    //为了安全起见。每次循环都需检查当前任务是否被取消。假设被取消这退出循环
                    if (isCancelled()) break;
                }
                return totalSize;
            }
    
            //该方法在后台任务运行之前运行。在UI线程中运行,用于初始化一些信息
            @Override
            protected void onPreExecute() {
                value = (TextView) findViewById(R.id.progress_value);
                progressBar = (ProgressBar) findViewById(R.id.progress);
                progressBar.setMax(100);
            }
    
            //该方法在UI线程中运行。用于获取后台任务更新的进度信息
            @Override
            protected void onProgressUpdate(Integer... values) {
                value.setText(values[0] + "%");
                progressBar.setProgress(values[0]);
            }
    
            //该方法在UI线程中运行,用于获取后台任务运行完毕之后的结果
            @Override
            protected void onPostExecute(Long aLong) {
                result.setText("the result is" + aLong);
                Toast.makeText(MainActivity.this, "the result is " + aLong, Toast.LENGTH_SHORT).show();
            }
        }
    }
    

    以上演示样例是一个最简单的模拟异步任务操作,我们基本的工作就是让子类DownloadFilesTask继承AsyncTask。然后重写对应的方法,当中仅仅要是重写的方法都无需用户去控制其调用逻辑,仅仅需重写里面的方法实现计算逻辑。言外之意就是:AsycnTask类中的那些方法的调用顺序是不须要用户去控制的,其内部已经控制好这些方法的调用逻辑。

    【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】

    AsyncTask源代码分析

    AsyncTask的构造方法

    public abstract class AsyncTask<Params, Progress, Result> {
        //获得当前运行状态的cup数
         private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
        //依据当前机器CUP的个数决定线程池中的线程个数
        private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
        //获得线程池中最大线程数
        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
        //线程的存活时间
        private static final int KEEP_ALIVE = 1;
        //线程工厂。为线程池创建所需线程
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
            private final AtomicInteger mCount = new AtomicInteger(1);
    
            public Thread newThread(Runnable r) {
                return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            }
        };
        //线程池中的缓存队列,此处为128个
        private static final BlockingQueue<Runnable> sPoolWorkQueue =
                new LinkedBlockingQueue<Runnable>(128);
    
        /**
         * An {@link Executor} that can be used to execute tasks in parallel.
         */
         //依据以上參数。构造线程池运行器
        public static final Executor THREAD_POOL_EXECUTOR
                = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    
        /**
         * An {@link Executor} that executes tasks one at a time in serial
         * order.  This serialization is global to a particular process.
         */
        //获得顺序运行的线程池运行器
        public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
        //异步任务处理结果码和进度更新码
        private static final int MESSAGE_POST_RESULT = 0x1;
        private static final int MESSAGE_POST_PROGRESS = 0x2;
        //内部类,消息的运行者handler对象
        private static final InternalHandler sHandler = new InternalHandler();
        //线程池中默认的运行器
        private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
        //异步任务回调接口
        private final WorkerRunnable<Params, Result> mWorker;
        private final FutureTask<Result> mFuture;
        //当前异步任务的状态。初始状态为“未运行”状态
        private volatile Status mStatus = Status.PENDING;
    
        private final AtomicBoolean mCancelled = new AtomicBoolean();
        private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    
    ......................
    
      /**
         * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
         */
        //创建一个新的异步任务,该构造方法必须在UI线程中调用
        public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                        mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    return postResult(doInBackground(mParams));
                }
            };
    
            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 occured while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        postResultIfNotInvoked(null);
                    }
                }
            };
        }
    ..................
    
    }

    分析:AsyncTask类中的全部成员变量的作用都已经加入凝视,在AsyncTask类的成员变量中依据当前系统CPU的个数来构建一个固定大小的线程池THREAD_POOL_EXECUTOR成员变量。然后通SerialExecutor类创建了一个顺序运行的线程池成员变量SERIAL_EXECUTOR,这里我们暂且不讨论SerialExecutor类的详细实现,仅仅需知道它是顺序运行的一个线程池运行器就可,感兴趣的童鞋能够深究。细心的你会发现AsyncTask的成员变量差点儿都是静态的。也就是说:一个应用中的内存中仅仅保存有一份这些成员变量的值。

    然后在构造方法中获得了mWorker对象,而且实现了里面的接口方法call,call方法里面调用了doInBackground方法。当后台线程任务被运行时,该call方法就会被调用。而且将mWorker作为參数传递给了FutureTask类来获取mFuture对象。因此在AsyncTask的构造方法中最后获得mFuture对象。FutureTask类也是继承自Runnable接口的。

    到此,我们能够理解成mFuture对象封装了一个后台的异步耗时任务,等待线程池运行器去处理该耗时任务。mFuture对象会作为一个线程接口在后面使用到。

    AsycnTask的运行方法execute

    由前面分析我们知道,AsyncTask处理异步任务的逻辑都在该类的内部实现了。我们仅仅须要重写对应的方法就可以。

    那么我们就从execute异步任务的运行方法開始跟踪AsyncTask类内部是怎么处理异步任务的逻辑的。

     /**
         * Executes the task with the specified parameters. The task returns
         * itself (this) so that the caller can keep a reference to it.
         * 
         * <p>Note: this function schedules the task on a queue for a single background
         * thread or pool of threads depending on the platform version.  When first
         * introduced, AsyncTasks were executed serially on a single background thread.
         * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
         * to a pool of threads allowing multiple tasks to operate in parallel. Starting
         * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
         * executed on a single thread to avoid common application errors caused
         * by parallel execution.  If you truly want parallel execution, you can use
         * the {@link #executeOnExecutor} version of this method
         * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
         * on its use.
         *
         * <p>This method must be invoked on the UI thread.
         *
         * @param params The parameters of the task.
         *
         * @return This instance of AsyncTask.
         *
         * @throws IllegalStateException If {@link #getStatus()} returns either
         *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
         *
         * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
         * @see #execute(Runnable)
         */
        public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return executeOnExecutor(sDefaultExecutor, params);
        }

    分析:该方法的凝视比方法的实现还多。大概意思是:传指定參数运行异步任务。该方法的返回值是AsyncTask对象本身。目的是让调用者持有AsyncTask对象的一个引用。该方法的功能是:不同平台利用不同方式去处理队列中的任务,AsyncTask最初设计是单个后台线程去处理队列中的任务。到了Android1.6版本号之后改为固定线程数的线程池去处理队列中的任务,在之后到了Android3.0之后。又改回到单个后台线程去处理队列中的任务,目的是为了解决Android1.6以后假设异步任务超过138个时AsyncTask会抛出异常。

    假设在Android3.0以后你想同一时候运行多个异步任务的话你能够使用AsyncTask类提供的executeOnExecutor方法实现。

    事实上execute方法的实现也仅仅是调用了executeOnExecutor方法而已。那么我们跟踪代码进入executeOnExecutor方法

    /** <p>This method must be invoked on the UI thread.
         *
         * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a
         *              convenient process-wide thread pool for tasks that are loosely coupled.
         * @param params The parameters of the task.
         *
         * @return This instance of AsyncTask.
         *
         * @throws IllegalStateException If {@link #getStatus()} returns either
         *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
         *
         * @see #execute(Object[])
         */
        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;
        }

    分析:凝视解释。该方必须在UI线程中调用。

    第一个參数为线程池运行器Executor对象。第二个參数为异步任务运行所需參数Params。

    方法的返回值为AsyncTask实例对象。
    1.代码第16-26行:推断当前异步任务状态,假设不是”PENDING“未运行状态,则会抛出对应的异常,假设是”RUNNING“,这抛出”Cannot execute task: the task is already running.”:当前任务正在运行;假设是”FINISHED”,则抛出Cannot execute task: the task has already been executed (a task can be executed only once)”:该任务已经被运行。

    由此可知AsyncTask同一个异步任务仅仅能被运行一次。

    2.代码第28行:标记当前异步任务的状态为”RUNNING”表示任务正在运行。

    3.代码第30行:调用onPreExecute方法,该方法是个空方法,在子类中能够重写该方法做一些初始化的工作,比方初始化进度条信息等。该方法运行与UI线程中。

    4.代码第32-33行:调用线程池运行器去处理异步任务mFuture。此处開始运行异步耗时任务,在线程中操作。由AsyncTask构造方法知道,mFuture是一个异步任务的封装。来看看FutureTask类中的run方法吧

    
    ...............
    
     public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            this.callable = callable;
            this.state = NEW;       // ensure visibility of callable
        }
    
    ........
    
    public void run() {
            if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                             null, Thread.currentThread()))
                return;
            try {
                Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran;
                    try {
                        result = c.call();
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;
                        ran = false;
                        setException(ex);
                    }
                    if (ran)
                        set(result);
                }
            } 
            ...............
        }

    分析:在FutureTask的构造方法中我们看到。将AsyncTask构造方法中的mWorker变量赋值给了FutureTask类中的callable变量。

    我们看到代码第24行调用了callable的call方法,因此这里调用例如以下接口方法

     mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    return postResult(doInBackground(mParams));
                }
            };

    有上面代码能够看出。在call方法中doInBackground方法的返回值作为參数传递给postResult方法,然后doInBackground是一个抽象方法。真正运行异步耗时任务的方法,详细实现须要在AsyncTask子类中实现。那么我们来看看postResult方法做了什么?

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

    该方法先通过getHandler方法获得一个Handler对象,然后将异步任务doInBackground方法返回的结果Result封装成消息发送出去,由 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制这篇博客我们知道。Handler消息处理机制是谁发送消息谁处理消息。那么我们来看看getHandler方法吧

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

    加锁获得Handler对象,目的是防止多线程同一时候持有Handler对象导致异步任务处理混乱情况。

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

    有上面代码能够看出,InternalHandler是AsyncTask类的内部类,然而InternalHandler是通过Looper.getMainLooper()UI线程的Looper作为參数构造的,因此InternalHandler是在UI线程中处理消息的。

    我们看到。上面有两条消息分支。

    1.MESSAGE_POST_RESULT:也就是调用了postResult方法之后发送的消息才走这条分支,将异步任务处理结果推送到UI线程中。此处又调用了finish方法。进入看看事实上现

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

    该方法表示异步任务处理结束。首先推断当前异步任务是否已经被取消,假设被取消则调用onCancelled方法,子类中假设想在异步任务取消时候做一些处理的话能够重写onCancelled方法。

    假设没有取消则调用onPostExecute方法。该方法的实现体是一个空,须要在子类中去实现拿到异步任务和处理结果。

    最后异步任务处理结束。将当前异步任务的状态置为FINISHED状态,以防止同一个任务被运行多次。

    2.MESSAGE_POST_PROGRESS:该条消息是用来公布异步任务进度信息的。最后会调用onProgressUpdate来公布进度信息到UI线程中,当中该方法是一个空的。须要子类去实现获得当前异步任务运行进度。那什么情况下发送了这条消息呢?我们查看代码发现,仅仅有AsyncTask类中的publishProgress方法里面发送了这条信息。那进入该方法看看

     /**
         * This method can be invoked from {@link #doInBackground} to
         * publish updates on the UI thread while the background computation is
         * still running. Each call to this method will trigger the execution of
         * {@link #onProgressUpdate} on the UI thread.
         *
         * {@link #onProgressUpdate} will not be called if the task has been
         * canceled.
         *
         * @param values The progress values to update the UI with.
         *
         * @see #onProgressUpdate
         * @see #doInBackground
         */
        protected final void publishProgress(Progress... values) {
            if (!isCancelled()) {
                getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                        new AsyncTaskResult<Progress>(this, values)).sendToTarget();
            }
        }
    

    方法的凝视解释:该方法须要在doInBackground方法中调用,目的是去更新当前异步任务运行进度。每调用一次该方法就会触发onProgressUpdate方法的调用,也就是每调用一次publishProgress方法就会发送一个消息码MESSAGE_POST_PROGRESS的消息到InternalHandler类处理。

    总结:由此可知,假设你想要在UI线程中获得当前异步任务运行的进度信息,就必须在onInBackground方法中调用publishProgress方法,否则就获取不到进度信息。

    cancel取消异步任务

    在网络请求的时候,当你退出当前Activity的时候你可能也想当前Activity启动的异步任务AsyncTask也随之取消。这么一来就节省了系统资源。在AsyncTask类中提供了cancel方法用来取消当前正在运行的异步任务。跟踪源代码查看AsyncTask#cancel

    /**
         * <p>Attempts to cancel execution of this task.  This attempt will
         * fail if the task has already completed, already been cancelled,
         * or could not be cancelled for some other reason. If successful,
         * and this task has not started when <tt>cancel</tt> is called,
         * this task should never run. If the task has already started,
         * then the <tt>mayInterruptIfRunning</tt> parameter determines
         * whether the thread executing this task should be interrupted in
         * an attempt to stop the task.</p>
         * 
         * <p>Calling this method will result in {@link #onCancelled(Object)} being
         * invoked on the UI thread after {@link #doInBackground(Object[])}
         * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
         * is never invoked. After invoking this method, you should check the
         * value returned by {@link #isCancelled()} periodically from
         * {@link #doInBackground(Object[])} to finish the task as early as
         * possible.</p>
         *
         * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
         *        task should be interrupted; otherwise, in-progress tasks are allowed
         *        to complete.
         *
         * @return <tt>false</tt> if the task could not be cancelled,
         *         typically because it has already completed normally;
         *         <tt>true</tt> otherwise
         *
         * @see #isCancelled()
         * @see #onCancelled(Object)
         */
        public final boolean cancel(boolean mayInterruptIfRunning) {
            mCancelled.set(true);
            return mFuture.cancel(mayInterruptIfRunning);
        }

    分析:方法的结束比方法实现体长,大概意思就是:调用该方法能够取消当前异步任务。假设当前的异步任务已经结束的话。返回false。否则返回true。

    该方法调用须要在doInBackground方法之后调用,调用此方法之后。应该确保不调用onPostExecute方法来公布异步任务结果到UI线程中。因此你应该在doInBackground方法中调用isCancelled方法去检查当前任务是否被取消,假设取消则尽早结束当前任务。

    有关cancel的參数问题:

    • 參数为true:当前正在运行异步任务的线程会马上中断
    • 參数为false:完毕当前正在运行的异步任务之后取消后面其它异步任务。

    最后给出一个AsyncTask内部逻辑流程图。便于大家直观的理解哪些方法运行与UI线程,哪些方法运行后台工作线程。

    这里写图片描写叙述

    AsyncTask陷阱

    非常多人可能都知道在Android3.0之前的AsyncTask类是有一个缺陷的,也就是当你同一时候运行139个异步任务的时候就会出错了。为什么会是这样子呢?全部玄机都在AsyncTask的运行方法execute里面。我们最好还是从Android2.3的AsyncTask源代码去解答该答案,在该版本号中的execute方法例如以下:

    public final AsyncTask<Params, Progress, Result> More ...execute(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;
            sExecutor.execute(mFuture);
    
            return this;
        }

    有上面代码能够发现,Android2.3版本号的execute方法实现和Android3.0以后的不一样,也就是上面我们分析的。在2.3版本号之前线程池运行器是这么构造的

    private static final int CORE_POOL_SIZE = 5;
       private static final int MAXIMUM_POOL_SIZE = 128;
        private static final int KEEP_ALIVE = 1;
    
        private static final BlockingQueue<Runnable> sWorkQueue =
                new LinkedBlockingQueue<Runnable>(10);
    
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
            private final AtomicInteger mCount = new AtomicInteger(1);
    
           public Thread More ...newThread(Runnable r) {
                return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            }
        };
    
        private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
                MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

    主要是构造一个固定线程为5,最大线程为128。缓存对了为10的一个线程池运行器。由此能够知道。当有第139个异步任务运行的时候就超出了最大线程数和缓存队列的总和。因此会报错。那么Android3.0以后的版本号是怎么解决问题的呢?

    在Android3.0以后的版本号AsyncTask类改动了execute方法的实现

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

    该方法又调用了executeOnExecutor方法去运行异步任务。此处使用的线程池运行器是sDefaultExecutor默认的运行器。有前面我们分析可得,默认的线程池运行器是一个顺序运行的。且缓存队列是无限大。也就是多个异步任务是顺序运行的。仅仅有当第一个异步任务运行完之后才干运行第二个,这么一来不管你有多少个异步任务,都不会报错。那有人可能会问?假设我须要在Android3.0以后的版本号上同一时候运行多个异步任务怎么办?哈哈。骚年,不用操心!Google Androidproject师早已给你想好了。在Anddroid3.0以后的AsyncTask类给暴露出一个接口也就是上面的executeOnExecutor方法啦,我们仅仅须要又一次构造一个线程池运行器,比方说你能够调用newCachedThreadPool方法来创建一个无线大的缓存线程池。能够同一时候运行无线个任务。

    //构建一个缓存线程池,用于同一时候运行无限多个异步耗时任务
    ExecutorService executorService = Executors.newCachedThreadPool();
    asyncTask.executeOnExecutor(executorService,params);

    开发人员能够依据项目需求选择自己合适的线程池运行器:

    • Single Thread Executor : 仅仅有一个线程的线程池,因此全部提交的任务是顺序运行,代码: Executors.newSingleThreadExecutor()
    • Cached Thread Pool : 线程池里有非常多线程须要同一时候运行,老的可用线程将被新的任务触发又一次运行,假设线程超过60秒内没运行,那么将被终止并从池中删除。代码:Executors.newCachedThreadPool()
    • Fixed Thread Pool : 拥有固定线程数的线程池,假设没有任务运行,那么线程会一直等待,代码: Executors.newFixedThreadPool()
    • Scheduled Thread Pool : 用来调度即将运行的任务的线程池,代码:Executors.newScheduledThreadPool()
    • Single Thread Scheduled Pool : 仅仅有一个线程,用来调度运行将来的任务,代码:Executors.newSingleThreadScheduledExecutor()

    总结: 在Android3.0之前的AsyncTask是有缺陷的。由于其内部使用了固定线程数和缓存大小的线程池来运行异步耗时任务。所以当同一时候有超过139个异步耗时任务时,AsyncTask就会报错。 然而在Android3.0以后的AsyncTask是没有缺陷的。由于其背部使用了一个顺序运行的线程池来运行异步耗时任务,不论有多少个异步任务每次都仅仅能运行一个,所以不会报错。

    且Android3.0之后的AsyncTask提供了自己定义线程池的方法,更加方便灵活的让开发人员依据自己所需来选择不同的线程池运行器来处理耗时任务。

    值得注意的是:假设你要兼容Android2.3以及3.0使用AsyncTask同一时候处理139个异步耗时任务是不可能的。这个时候你仅仅能自己利用 Handler+Message+ThreadPool+Exexutor自己构建一个异步任务处理框架了。考验你技术的时候到啦。事实上你能够仿着3.0的AsyncTask写一个就好了。

    AsyncTask总结

    1.AsyncTask类仅仅能在UI线程中使用,为什么?能够看 AsycnTask的运行方法execute小节。由于里面的Handler是有MainLooper构造的。

    2.刚開始学习的人可能会有这个疑问?一个App应用中有非常多个异步耗时任务,每一个任务都去创建一个AsyncTask对象岂不是非常耗费资源?假设这么想你就还不理解AsyncTask了。从AsyncTask的构造方法小节能够看到,里面的绝大多数成员变量都是静态static的。包含Executor运行器。

    因此整个应用都是共享且仅仅有一个AsyncTask实例的。

    3.关于AsyncTask类中的方法调用逻辑无需用开发人员去关注。开发人员仅仅须要重写对应的方法就可以。

    当然假设你想在UI线程中获得进度信息,你就必须在doInBackground方法中调用publishProgress方法才干够触发UI线程中的onProgressUpdate方法来更新进度信息。

    4.值得一提的是:在你重写doInBackground方法运行异步耗时任务时。你最好在适当的地方调用

    if (isCancelled()){
    //做一些任务取消的处理
    }

    此方法调用的目的是检測在运行异步耗时任务时该任务是否已经被取消了?假设被取消了。当前正在运行的异步任务就没有必要继续运行了。节省资源。比方博客开头的样例:异步任务是一个循环任务,假设在运行到第2个循环的时候异步任务被取消了。此时就跳出循环结束此次的异步任务。

    5.在Android3.0之前假设你想要同一时候运行超过139个异步任务的时候,AsyncTask是会报错的,这时候你就不得不自己去又一次构造一个多线程异步任务处理框架了,就不能直接使用AsyncTask框架了。可是在Android3.0之后改善了这个问题。3.0之后默认是顺序运行异步任务,不管你有多少个异步任务都不会报错,你也能够自己定义一个符合需求的线程池运行器。

    【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】

  • 相关阅读:
    删除数据时弹出一个确认对话框
    制作一个页面弹出窗口
    网页授权——扫二维码获取openid
    删除自定义菜单
    创建自定义菜单
    微信公众平台开发接口PHP SDK
    上传文件
    Fibonacci
    最大公约数和最小公倍数
    完数【转载】
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7272603.html
Copyright © 2020-2023  润新知