美文网首页
Android 多线程:AsyncTask理解和使用总结

Android 多线程:AsyncTask理解和使用总结

作者: Marker_Sky | 来源:发表于2017-10-19 20:40 被阅读0次
    AsyncTask目录.png

    一、AsyncTask介绍

    1.1 作用:

    轻量级的异步类,同时方便在子线程更新UI。

    1.2 原理:

    封装了Handler和两个线程池。AsyncTask的源码链接

    1. 线程池THREAD_POOL_EXECUTOR:通过ThreadFactory和一些参数实例化线程池THREAD_POOL_EXECUTOR用于执行任务
    2. 线程池SERIAL_EXECUTOR:内部类SerialExecutor实现Executor也是一个线程池,实例化对象SERIAL_EXECUTOR执行SerialExecutor定义的execute方法来串行(一个一个按顺序)排队任务并使用THREAD_POOL_EXECUTOR来执行任务
    3. AsyncTask创建时会实例化一个WorkerRunnable对象mWorker和一个FutureTask对象mFuture。FutureTask是一个并发类,充当Runnable的作用。AsyncTask执行任务时把mFuture作为排队线程池SerialExecutor的execute(final Runnable r)的参数传递,接着会串行排队并使用工作线程来处理实际任务。
    4. mFuture对象创建时把mWorker对象作为参数传递,在mFuture在执行任务run()时会调用mWorker的call()方法,因此call()方法是在线程池中进行的。
    5. 主线程的Handler:然后call()方法里面接着调用result = doInBackground(mParams);并返回Result对象,这个过程中任务被取消会catch跳出设置AsyncTask结束。call()方法最后postResult(result);获取主线程的Handler发送消息并根据消息类型判定更新UI或者结束AsyncTask。
      具体参考:源码解析Android中AsyncTask的工作原理

    1.3 参数以及核心函数

    AsyncTask是一个泛型类,在android.os包下

    AsyncTask类.png
    泛型内三个参数定义的是我们需要的数据的类型,如果不需要传递参数,可以用Void来代替,以下是具体含义:
    • Params:参数的类型;
    • Progress:后台任务的执行进度类型;
    • Result:后台任务返回结果的类型。
      AsyncTask还提供了4个核心方法:
    1. protected void onPreExecute():在主线程执行,异步任务执行前调用做准备工作;
    2. protected abstract Result doInBackground(Params... var1):在线程池中执行,用于执行异步任务。Params表示异步任务输入参数,可以在此方法中通过publishProgress方法来更新任务进度,publishProgress方法又调用onProgressUpdate方法实现主线程进度更新。这个方法返回ResultonPostExecute方法。
    3. protected void onProgressUpdate(Progress... values):在主线程执行,后台任务执行进度发生变化会调用此方法。
    4. protected void onPostExecute(Result result):在主线程执行,异步任务执行后调用,result参数是由doInBackground返回的。

    这四个方法执行的顺序为:onPreExecute(准备)-->doInBackground(后台异步)-->onPostExecute(结果处理)
    还有一个有用的方法:protected void onCancelled():当异步任务取消时调用,而这时候onPostExecute不会被调用。

    二、AsyncTask使用

    2.1 AsyncTask使用示例:

    (1) 创建Activity,布局两个按钮用来开始和取消AsyncTask,一个TextView来显示状态。

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:id="@+id/btn_download"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="开始下载"/>
    
        <Button
            android:id="@+id/btn_cancel"
            android:layout_below="@id/btn_download"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="取消下载"/>
    
        <TextView
            android:id="@+id/tv_statue"
            android:layout_below="@id/btn_cancel"
            android:textSize="15sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </RelativeLayout>
    

    (2) 创建内部类自定义MyAsyncTask继承AsyncTask,重写四个主要方法:

      //第一个参数:Params参数类型:String类型 
      //第二个参数:Progress执行进度类型:Object类型 
      //第三个参数:Result参数类型:Long类型
      private class MyAsyncTask extends AsyncTask<String,Object,Long>{
      ...
      @Override
      protected void onPreExecute() {...}
    
      @Override
      protected Long doInBackground(String... strings) {...}
    
      @Override  
      protected void onProgressUpdate(Object... values) {...}
    
       @Override
       protected void onPostExecute(Long aLong) {...}
    
      @Override //任务取消调用
      protected void onCancelled() {...}
    

    (3)开始按钮调用创建MyAsyncTask并执行downloadTask.execute(urls)传入参数。

    mDownButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String[] urls = {
                    "http://www.jianshu.com/p/d3984e7e204f",
                    "http://www.jianshu.com/p/8e3cfb87f35e",
                    "http://www.jianshu.com/p/4fbc2ea2e02b"
            };
            downloadTask = new MyAsyncTask();
            // 这里的url也可以分成一个一个参数传递
            downloadTask.execute(urls);
        }
    });
    

    (4) 取消按钮调用downloadTask.cancel(true)停止MyAsyncTask。

    //取消按钮点击事件
    downloadTask.cancel(true);
    

    (5) doInBackground(String... strings)方法循环执行下载任务并返回result,是自己定义的二维数组,第一个是字节数,第二个是文章标题。

    protected Long doInBackground(String... strings) {
        long totalByte = 0;
        for (String url:strings){
            // downloadFile方法只是一个简单的下载字节流
            // 返回的Object[] result是二维数组,一个是下载的字节数,一个是标题
            Object[] result = downloadFile(url);
            int byteCount = (int) result[0];
            totalByte += byteCount;
            //传递进度
            publishProgress(result);
            // 异步任务调用取消则跳出for循环
            if(isCancelled()){
                break;
            }
        }
        return totalByte;
    }
    

    (6) 然后使用publishProgress(result);把数据传递给onProgressUpdate(Object... values)方法来更新UI,这个方法已经切换到了主线程,所以可以更新UI。AsyncTask完成后onPostExecute(Long aLong)方法自动调用再次来更新状态。

      @Override
      protected void onPostExecute(Long aLong) {...}
    

    看一下效果,源码我会在后面放出,取消下载请自行测试。


    AsyncTaskDemo.gif

    2.2 AsyncTask使用注意:

    1. AsyncTask的类必须在主线程加载。
    2. AsyncTask的对象必须在主线程创建。
    3. execute方法必须在UI线程调用。
    4. 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则报运行时异常。
    5. 在Android1.6之前,AsyncTask是串行执行任务的,Android1.6的时候AsyncTask开始使用线程池处理并行任务,但是从Android3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程串行执行任务。尽管如此,在Android3.0以及后续的版本中,我们仍然可以通过AsyncTask的executeOnExecutor方法来并行地执行任务。

    三、AsyncTask优点和缺点

    3.1 优点:

    1. 简单快捷,使用方便。
    2. UI更新及时,过程可控。

    3.2 缺点:

    多个异步操作需要更新UI时,就变得麻烦起来。

    3.3 其它问题:

    参考文章:AsyncTask的缺陷和问题

    目录文章:
    Android多线程:理解和简单使用总结

    相关文章

      网友评论

          本文标题:Android 多线程:AsyncTask理解和使用总结

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