美文网首页
AsyncTask 第一篇使用篇

AsyncTask 第一篇使用篇

作者: 王三的猫阿德 | 来源:发表于2016-04-03 12:01 被阅读137次

    转载注明出处:http://www.jianshu.com/p/cd2d9635f436

    AsyncTask简介

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

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

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

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

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

    在一个按钮的点击事件中执行了上述代码,我们来看一下运行结果吧。

    图1 - 运行结果

    从日志上看,日志的输出好像就是这四个方法的顺序!!当然方法的顺序是随便可以变的,主要是方法调用的时机,掌握了AsyncTask暴露的方法调用的时机,就很好理解AsyncTask了。在了解方法调用顺序之前,我们先来看一下AsyncTask类的几个泛型的含义。

    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这里面几个方法的调用时机和顺序的图,相信大家一下子就会明白。

    图2 - 方法执行顺序

    注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里面的内部实现。

    相关文章

      网友评论

          本文标题:AsyncTask 第一篇使用篇

          本文链接:https://www.haomeiwen.com/subject/lmlulttx.html