AsyncTask 第一篇使用篇

来源:互联网 发布:区域软件 编辑:程序博客网 时间:2024/04/30 03:16

转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/52024555

1. AsyncTask简介

       在手机中耗时的操作比较多,比如说扫描本地的文件夹,比如说从网上下载东西,我们希望这些操作在后台运行,于是我们开了一个线程在后台去执行这些耗时操作。但是仅仅在后台执行操作并不是一个很友好的交互体验,是否可以将操作执行的状态以百分比显示出来?是否可以将执行的结果直接返回到UI层,让用户更直观的了解到操作的状态和结果,这就会涉及异步消息处理的机制了。

       如果看过上一篇Handler异步消息处理机制,从源代码看起的同学很快会想到,我们可以开起一个线程,在线程中利用Handler将执行的状态传到UI线程,继而更新UI。

       思路很正确,同时官方也提供了更有效的方法—AsyncTask,AsyncTask是Android官方提供的一个轻量级的异步类,用于处理异步消息,允许在后台执行一些任务,然后将执行结果返回给UI层,无需操作线程或者使用Hanlder。它仅仅是一个线程与Handler之间的帮助类,并不是一个通用的线程框架。

我们先来看看怎么使用它吧。

2. AsyncTask使用

直接上代码。

public class MyAsyncTask extends AsyncTask<String, Integer, String> {    /**     * 操作进度     */    private int process = 0;    @Override    protected void onPreExecute() {        Log.d("wang", "start task");    }    @Override    protected String doInBackground(String... params) {        Log.d("wang", "param is " + params[0]);        try {            while(process < 100) {//模拟任务进度到达100                //模拟耗时操作,线程挂起0.5s                Thread.sleep(500);                process = process + 10;                publishProgress(process);            }            //耗时操作完成后,停顿0.5s缓冲,然后返回结果            Thread.sleep(500);        } catch (InterruptedException e) {            e.printStackTrace();        }        return "task completed";    }    @Override    protected void onProgressUpdate(Integer ... progress) {        Log.d("wang", progress[0] + "%");    }    @Override    protected void onPostExecute(String result) {        Log.d("wang", result);    }}

自定义了一个MyAsyncTask的类,继承自AsyncTask并复写了一些方法,方法的具体作用后面会讲到。

new MyAsyncTask().execute("Hello World");

在一个按钮的点击事件中执行了上述代码,我们来看一下运行结果吧。
运行结果
       从日志上看,日志的输出好像就是这四个方法的顺序!!当然方法的顺序是随便可以变的,主要是方法调用的时机,掌握了AsyncTask暴露的方法调用的时机,就很好理解AsyncTask了。在了解方法调用顺序之前,我们先来看一下AsyncTask类的几个泛型的含义。

3. AsyncTask说明

       AsyncTask< Params, Progress, Result >,第一个代表执行AsyncTask时候参数的数据类型,就是调用mAsyncTask.excute(params)时候传入的参数,第二个代表在执行过程中记录运行状态的数据类型,第三个代表任务执行完毕后,返回的数据类型。

注:Params Progress Result可以代表任意数据类型(泛型)

然后我们再来看一看这四个方法,四个方法从方法名称就能理解个大概,来详细了解一下吧。

  • onPreExecute(),这个方法是在AsyncTask任务执行之前做的一些操作,UI线程
  • doInBackground(Params params),这个方法是在后台线程主要执行的方法,非UI线程。入参是执行AsyncTask传入的参数,返回的结果是任务执行的结果,最终会将结果传递到onPostExecute方法中
  • onProgressUpdate(Progress progress),这个方法是在后台线程执行过程时候,更新执行状态的,UI线程
  • onPostExecute(Result result),这个方法是后台线程执行完毕之后返回的一个结果回调 UI线程
  • publishProgress(Progress progress),这个方法是在后台线程执行时候,将执行状态发送出去

       细心人会发现,不是说只有四个方法吗?为什么我写了五个,多了一个publishProgress方法?其实在我们自定义AsyncTask的时候,只需要复写前面四个方法就可以了(必须实现的方法只有doInBackground其他三个方法可以不复写),但是更新执行状态onProgressUpdate这个行为,AsyncTask里面默认是不调用的,需要我们手动在doInBackground方法里面调用publishProgress方法,这样我们的AsyncTask才会执行onProgressUpdate方法。

如果还没有理解透彻的话,我们来看一下AsyncTask这里面几个方法的调用时机和顺序的图,相信大家一下子就会明白。
方法执行顺序
       注1:黄色背景代表UI线程,蓝色背景代表非UI线程
       注2:虚线代表调用熟悉,实线代表内部调用关系
       在执行后台任务之前,先会执行onPreExecute方法,然后紧接着会在非UI线程执行doInBackground方法,这个方法接受的参数就是AsyncTask调用时候传入的参数,如果在doInBackground方法里面手动调用了publishProgress方法,onProgressUpdate方法也会被执行,注意这个两个方法的入参的数据类型是相同的,非UI线程执行完任务之后,会把结果返回,onPostExcute方法就会被执行。

Tips

  • AsyncTask必须在UI线程实力化,调用它也必须在UI线程
  • 不要手动的去调用上文中提到的几个可以复写的方法,onPreExecutedoInBackgroundonProgressUpdateonPostExecute方法
  • 每一个实例化的AsyncTask只能被执行一次,也就是说mMyAsyncTask.execute(parasm)多次调用时会报错。
  • AsyncTask内部的异步消息处理实际上是使用的Handler
  • AsyncTask的具体任务的执行是在非UI线程中,这些线程是放在一个线程池中,线程池中默认最多支持128个线程
  • doInBackground是在非UI线程执行的,onPreExecuteonProgressUpdateonPostExecute是在UI线程执行的,可以在这三个方法里面进行UI操作。
  • 待完善…

总结

总体说来,AsyncTask使用起来还是比较方便的,能够解决很多场景下的异步消息问题,同时它能够将执行任务的结果返回,在很多场景下是非常有用的。
下一篇本来是从源代码开始分析AsyncTask内部的具体实现,但是涉及到一些线程方面的知识,所以下一篇是讲解一些线程方面的基础知识,第三篇从源代码分析AsyncTask里面的内部实现。

0 0
原创粉丝点击