Android中的AsyncTask

来源:互联网 发布:后台数据集 js调用 编辑:程序博客网 时间:2024/06/06 01:25

AsyncTask有两种运行的方式,串行和并行。

以下是我做的一个测试例子有串行和并行,代码如下,可以看到两种方式的不同。


package com.example.xueqin.asynctaskdemo;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.support.annotation.Nullable;import android.view.View;import android.widget.Button;import android.widget.ProgressBar;/** * Created by xue.qin on 2017/6/12. */public class MainActivity extends Activity implements View.OnClickListener {    Button button;    ProgressBar progressBar1, progressBar2, progressBar3, progressBar4;    Integer[] params = {0, 1, 2, 3};    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main_activity_layout);        progressBar1 = (ProgressBar) findViewById(R.id.progressbar1);        progressBar2 = (ProgressBar) findViewById(R.id.progressbar2);        progressBar3 = (ProgressBar) findViewById(R.id.progressbar3);        progressBar4 = (ProgressBar) findViewById(R.id.progressbar4);        button = (Button) findViewById(R.id.start);        button.setOnClickListener(this);    }    @Override    public void onClick(View v) {        MyAsyncTask myAsyncTask1 = new MyAsyncTask();        MyAsyncTask myAsyncTask2 = new MyAsyncTask();        MyAsyncTask myAsyncTask3 = new MyAsyncTask();        MyAsyncTask myAsyncTask4 = new MyAsyncTask();        //并行调用        myAsyncTask1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0);        myAsyncTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 1);        myAsyncTask3.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 2);        myAsyncTask4.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 3);        //串行调用//        myAsyncTask1.execute(0);//        myAsyncTask2.execute(1);//        myAsyncTask3.execute(2);//        myAsyncTask4.execute(3);    }    class MyAsyncTask extends AsyncTask<Integer, Integer, String> {        private int index = 0;        @Override        protected String doInBackground(Integer... params) {            index = params[0];            int increase = 0;            while (increase <= 100) {                try {                    Thread.sleep(50);                } catch (InterruptedException e) {                    e.printStackTrace();                }                publishProgress(increase++);            }            return "complete";        }        @Override        protected void onProgressUpdate(Integer... values) {            switch (index) {                case 0:                    progressBar1.setProgress(values[0]);                    break;                case 1:                    progressBar2.setProgress(values[0]);                    break;                case 2:                    progressBar3.setProgress(values[0]);                    break;                case 3:                    progressBar4.setProgress(values[0]);                    break;                default:                    break;            }        }    }}


并行调用:进度条是一起滚动的,如图



串行调用时依次进行的如图



源码分析。

1)第一种,串行调用,使用默认的线程池,来运行,调用下面的这个函数

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

接着调用这个executeOnExecutor()这里没有

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


这里没什么说的,这个mFuture是在无参数的构造函数(必会被调用)中将我们重写的doInBackground(),包装成WorkerRunnable,又包了一层变成了FutureTask。

总之提交这个mFuture到线程池中执行,就会调用doInBackground()里的代码。

看一下这个sDefaultExecutor执行的代码:

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


这里的逻辑应该是这样的,当第一次执行execute()时,mActive==null,执行scheduleNext(), 这里将Runnable提交到线程池运行,运行之后finnally继续调用scheduleNext()直到mTasks中没有runnable,所以是串行执行的。

这样的好处:

连续执行execute,只在第一次,开始scheduleNext(),之后自动调用,这中间,还是可以不断的向mTask中添加Runable,也就是说总会排队执行完所用的execute的runnable。

执行完成之后,下一次提交又是进入下一个循环。

scheduleNext为什么加锁:因为主线程和线程池都会调用到这个函数,不加锁,可能会重复调用,那么就有可能有并行的情况出现。ArrayDeque也不是线程安全的,会出现runnable重复执行等很多问题。同理execute也是因为ArrayDeque线程的不安全,可能会有在同一个index提交两个runnable,之前的就被顶掉了,等各种情况出现。

2)并行调用。

直接使用上面提到的executeOnExecutor这个函数,自定义线程池来调用。AsyncTask中已经写好了一个线程池,如下:

public static final Executor THREAD_POOL_EXECUTOR;    static {        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,                sPoolWorkQueue, sThreadFactory);        threadPoolExecutor.allowCoreThreadTimeOut(true);        THREAD_POOL_EXECUTOR = threadPoolExecutor;    }

并使用静态块初始化了这个线程池。可以使用以下代码来使用这个线程池来调用,这个自然就是并行的了。

myAsyncTask1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0);        myAsyncTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 1);        myAsyncTask3.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 2);        myAsyncTask4.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 3);



原创粉丝点击