AsyncTask使用与源码解析

安卓更新UI的方式大致有四种:

  • 使用Handler消息传递机制;
  • 使用AsyncTask异步任务;
  • 使用runOnUiThread(action)方法;
  • 使用Handler的post(Runnabel r)方法;

其中AsyncTask和Handler是两种异步方式。我有一篇文章专门讲解Android异步消息处理机制 Handler、Looper、Message这篇文章,从源码讲解,很适合看。

今天我们着重通过示例来讲解AsyncTask。

AsyncTask是什么?作用是什么?

AsyncTask可以理解为异步任务执行者,主要用来执行一个较为耗时的异步任务,然后更新UI。

AsyncTask的调用步骤

AsyncTask是抽象类,定义了三种泛型类型 Params,Progress,Result。

  • 1) Params 启动任务执行的输入参数,比如HTTP请求的URL。调用execute()方法时传入的参数类型和doInBackgound()的参数类型

  • 2) Progress 后台任务执行的百分比。更新进度时传递的参数类型,即publishProgress()和onProgressUpdate()的参数类型

  • 3) Result 后台执行任务最终返回的结果,比如String。即doInBackground()的返回值类型。

使用步骤:

  • 首先实例化AsyncTask

  • 接着实现AsyncTask中定义的下面一个或几个方法

onPreExecute(),该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params…),将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

onProgressUpdate(Progress…),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result),在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

下面通过代码示例来讲解。

Activity代码(里面包含全部内容,文末也有github地址):
public class AsyncTaskActivity extends AppCompatActivity {
    private List<TextView> mTextViewList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task);
        mTextViewList = new ArrayList<>();
        mTextViewList.add((TextView) findViewById(R.id.asyntask_one));
        mTextViewList.add((TextView) findViewById(R.id.asyntask_two));
        mTextViewList.add((TextView) findViewById(R.id.asyntask_three));
        mTextViewList.add((TextView) findViewById(R.id.asyntask_four));
        mTextViewList.add((TextView) findViewById(R.id.asyntask_five));
        mTextViewList.add((TextView) findViewById(R.id.asyntask_six));
        new MyAsyncTask(mTextViewList.get(0), 0).execute();
        new MyAsyncTask(mTextViewList.get(1), 1).execute();
        new MyAsyncTask(mTextViewList.get(2), 2).execute();
        new MyAsyncTask(mTextViewList.get(3), 3).execute();
        new MyAsyncTask(mTextViewList.get(4), 4).execute();
        new MyAsyncTask(mTextViewList.get(5), 5).execute();


    }


    private class MyAsyncTask extends AsyncTask<Void, Integer, String> {//here to shengshi use void
        private TextView mTextView;
        private int id;

        /**
         * 生成该类的对象,并调用execute方法之后
         * 首先执行的是onProExecute方法
         * 其次执行doInBackgroup方法
         */


        public MyAsyncTask(TextView textView, int id) {
            super();
            mTextView = textView;
            this.id = id;
        }

        //运行在UI线程当中,并且运行在UI线程,可以对UI进行设置
        @Override
        protected void onPreExecute() {
            mTextView.setText("task " + id + "  即将开始执行异步线程");
        }

        @Override
        protected String doInBackground(Void... params) {

            NetOperator netOperator = new NetOperator();
            int i = 0;
            for (i = 0; i <= 2000; i += 100) {
                netOperator.operator();
                publishProgress(i / 200);//这是更新的进度
            }

            return id + " 的图片下载完成";//返回的是最后的String结果
        }


        //在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
        @Override
        protected void onProgressUpdate(Integer... values) {
            mTextView.setText("task " + id + "   异步操作执行到  " + values[0] + " 进度");
        }

        //运行在UI线程当中,并且运行在UI线程,可以对UI进行设置

        @Override
        protected void onPostExecute(String s) {
            mTextView.setText("task " + id + "  异步操作执行结束 " + s);
        }
    }


    //模拟加载环境,做一个耗时操作
    public class NetOperator {

        public void operator() {
            try {
                //休眠0.01秒
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

通过观察,我们看出了通过execute来启动AsyncTask的话,他是串行执行的。

下面改变一下执行方法executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)

从上面我们可以看出,AsyncTask即可以串行执行,又可以并行执行,关键是看你怎么启动它

进入源码看一下他的执行
  @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;
    }

可以看出来使用execute方法最终还是执行executeOnExecutor方法,只不过是里面传的参数不一样。

我们来分析一下sDefaultExecutor,THREAD_POOL_EXECUTOR这两个参数,为何导致执行结果不同。

THREAD_POOL_EXECUTOR:

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     * 可以用来并行执行任务的
     */
    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;//THREAD_POOL_EXECUTOR就是一个线程池
    }

看一下其中相关的参数:

   private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//CORE_POOL_SIZE是核心线程数量,从2和(CPU核心-1与4中的最小值)取最大值
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大线程数量
    private static final int KEEP_ALIVE_SECONDS = 30;//保活时间为30s

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

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);//线程池的任务队列中可以同时有128个任务等待执行

我们现回头看executeOnExecutor方法,传入的是THREAD_POOL_EXECUTOR线程池,exec.execute方法中调用的就是THREAD_POOL_EXECUTOR的execute方法,任务就会在这个线程池中运行,调用这个方法,至少会有两个任务一起执行。

接着我们来看sDefaultExecutor

每天都在加班,太累了,明天接着分析,不好意思。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值