这次我真的懂AsyncTask了

在研究学习AsyncTask的过程中,在看了源码以及郭霖大神的Android AsyncTask完全解析,带你从源码的角度彻底理解 之后仍然有一段代码不懂。

private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

这段代码我当然能看懂这是一个线性的线程池,将任务一个一个的线性执行,但我不理解的是AsyncTask里也没有提交任务的接口啊,哪来那么多任务的啊?

后来我看到了下面的代码:

    /**
     * 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();

啊~原来这个默认Executor是static的啊~抱歉抱歉,我脑子瓦特了,也就是说所有继承了AysncTask的类在运行时都是在同一个线程池里的啊~~

傻fufu

然后我做了以下的试验,验证了这个结论:

首先自定义了一个DownloadFilesTask ,用Thread.sleep(5000)模拟下载任务耗时了5秒:

public class DownloadFilesTask extends AsyncTask<String, Integer, String> {

    private static final String TAG = "DownloadFilesTask";

    private int taskID;

    public DownloadFilesTask(int id) {
        taskID = id;
    }

    @Override
    protected String doInBackground(String... url) {
        Log.d(TAG, "DownLoad Start: TaskID = "+taskID);
        try{
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "DownLoad Completed: TaskID = "+taskID;
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        //setProgressPercent(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d(TAG, result);
    }
}

然后在MainActivity中执行:

public class MainActivity extends AppCompatActivity {

    private final Executor exec = new ThreadPoolExecutor(15, 200, 10,
            TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DownloadFilesTask task1 = new DownloadFilesTask(1);
        DownloadFilesTask task2 = new DownloadFilesTask(2);

        //使用默认线性线程池
        task1.execute("www.baidu.com");
        task2.execute("www.google.com");

        /*//使用自定义线程池
        task1.executeOnExecutor(exec, "www.baidu.com");
        task2.executeOnExecutor(exec, "www.google.com");*/
    }
}

使用默认线性线程池的情况下,两个任务应该是线性执行,task1完成后,task2才会开始执行:

11-26 11:27:19.583 26628-26644/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Start: TaskID = 1
11-26 11:27:24.584 26628-26628/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Completed: TaskID = 1
11-26 11:27:24.587 26628-26666/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Start: TaskID = 2
11-26 11:27:29.588 26628-26628/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Completed: TaskID = 2

但如果使用我们自定义的线程池,那么两个任务将是并行执行,运行的总时间将缩减:

11-26 11:29:44.147 26906-26922/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Start: TaskID = 1
11-26 11:29:44.148 26906-26923/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Start: TaskID = 2
11-26 11:29:49.149 26906-26906/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Completed: TaskID = 1
11-26 11:29:49.150 26906-26906/com.cr.asynctasktest D/DownloadFilesTask: DownLoad Completed: TaskID = 2

总结

这样给了我们一个启示,如果你的应用里定义了多个AsyncTask,在一个模块内同时启动了,如果使用了execute方法,那么将是线性执行,总时间将会变长;如果你的模块是时间敏感的,那么最好使用executeOnExecutor方法并行执行,这样运行时间将会缩短,但是有一个问题,你的线程池得依据你的业务小心设计,因为任务之间或许有前后顺序的依赖,或者同时任务太多,线程池大小设定过小,也会发生崩溃。

扫描二维码关注公众号,回复: 2857592 查看本文章

猜你喜欢

转载自blog.csdn.net/qugename/article/details/78636367
今日推荐