AsyncTask是什么鬼

Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制,在Android中实现异步任务机制有两种方式,Handler和AsyncTask。Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制,AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。

    public abstract class AsyncTask<Params, Progress, Result> {  

有三个泛型参数:
三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替。
一个异步任务的执行一般包括以下几个步骤:
1.execute(Params… params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。(手动调用)

2.onPreExecute(),在execute(Params… params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。(进度条初始化)

3.doInBackground(Params… params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress… values)来更新进度信息。

4.onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。

5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。

在使用的时候,有几点需要格外注意:
1.异步任务的实例必须在UI线程中创建。
2.execute(Params… params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法.(会自定执行)
4.不能在doInBackground(Params… params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
看一个例子

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {

    private ImageView imageView;
    private Button button;
    private String urlString = "http://images.china.cn/attachement/jpg/site1000/20150616/002564bb20a216e9add813.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.imageView_main_show);
        button = (Button) findViewById(R.id.button_main_download);
        button.setOnClickListener(new View.OnClickListener() {  
            @Override
            public void onClick(View v) {
                new DownloadImageTask(MainActivity.this).execute(urlString);
            }
        });
    }
    /*
     * Params:输入任务的参数:doInBackground()方法的参数、execute()方法的参数
     * Progress:任务执行是的进度指示:onProgressUpdate()方法的参数、publishProgress()方法的参数
     * Result:任务执行的结果:doInBackground()方法的返回值、onPostExecute()方法的参数
     */
    class DownloadImageTask extends AsyncTask<String, Integer, Bitmap> {    
        private ProgressDialog progressDialog;
        private Context context;
        public DownloadImageTask(Context context) {
            this.context = context;
            progressDialog = new ProgressDialog(context);       progressDialog.setIcon(R.drawable.ic_launcher);
            progressDialog.setTitle("提示信息");
            progressDialog.setMessage("正在努力为您加载...");       progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setMax(100);     
            // 为Dialog添加取消监听
        progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {         
                @Override
                public void onCancel(DialogInterface dialog) {              
                    // 取消异步任务
                    cancel(true);
                }
            });
        }

        // 该方法在主线程中调用
        @Override
        protected void onPreExecute() {
            progressDialog.show();
            super.onPreExecute();
        }

        // 该方法在子线程中调用
        @Override
        protected Bitmap doInBackground(String... params) {
            InputStream inStream = null;
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            try {
                URL url = new URL(params[0]);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setReadTimeout(5000);
                conn.setDoInput(true);
                conn.setRequestMethod("GET");
                conn.connect();
                if (conn.getResponseCode() == 200) {
                    inStream = conn.getInputStream();
                    byte[] buffer = new byte[512];
                    int length = 0;

                    // 要下载文件的总长度
                    int fileLength = conn.getContentLength();

                    // 已经下载的文件长度
                    int downloadLength = 0;


                    while ((length = inStream.read(buffer)) != -1) {
                        outStream.write(buffer, 0, length);

                        // 计算的出当前的进度值
                        downloadLength += length;
                        int progress = (int) ((downloadLength / (float) fileLength) * 100);

                        // 发布进度,引起onProgressUpdate()方法的调用
                        publishProgress(progress);

                        if (isCancelled()) {
                            outStream = null;
                            break;
                        }
                    }

                    if (outStream != null) {
                        byte[] imgData = outStream.toByteArray();
                        Bitmap imgBitmap = BitmapFactory.decodeByteArray(imgData, 0, imgData.length);
                        return imgBitmap;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (inStream != null) {
                    try {
                        inStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }

        // 该方法在主线程中调用
        @Override
        protected void onProgressUpdate(Integer... values) {

            // 使用ProgressDialog显示进度值
            progressDialog.setProgress(values[0]);
            super.onProgressUpdate(values);
        }

        // 该方法在主线程中调用
        @Override
        protected void onPostExecute(Bitmap result) {
            progressDialog.dismiss();
            if(result != null) {
                imageView.setImageBitmap(result);
            } else {
                Toast.makeText(MainActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
            }
            super.onPostExecute(result);
        }

        // 该方法在主线程中调用
        @Override
        protected void onCancelled(Bitmap result) {
            Toast.makeText(context, "取消了下载", Toast.LENGTH_SHORT).show();
            super.onCancelled(result);
        }

    }

}

AsyncTask是对Thread+Handler良好的封装,在android.os.AsyncTask代码里仍然可以看到Thread和Handler的踪迹
这里写图片描述

我们可以看到关键几个步骤的方法都在其中,doInBackground(Params… params)是一个抽象方法,我们继承AsyncTask时必须覆写此方法;onPreExecute()、onProgressUpdate(Progress… values)、onPostExecute(Result result)、onCancelled()这几个方法体都是空的,我们需要的时候可以选择性的覆写它们;publishProgress(Progress… values)是final修饰的,不能覆写,只能去调用,我们一般会在doInBackground(Params… params)中调用此方法;另外,我们可以看到有一个Status的枚举类和getStatus()方法,Status枚举类代码段如下:

      //初始状态  
    private volatile Status mStatus = Status.PENDING;  

    public enum Status {  
        /** 
         * Indicates that the task has not been executed yet. 
         */  
        PENDING,  
        /** 
         * Indicates that the task is running. 
         */  
        RUNNING,  
        /** 
         * Indicates that {@link AsyncTask#onPostExecute} has finished. 
         */  
        FINISHED,  
    }  

/** 
     * Returns the current status of this task. 
     * 
     * @return The current status. 
     */  
    public final Status getStatus() {  
        return mStatus;  
    }  

根据静态代码块的执行顺序,AsyncTask的初始状态为PENDING,代表待定状态,RUNNING代表执行状态,FINISHED代表结束状态,这几种状态在AsyncTask一次生命周期内的很多地方被使用,非常重要。

介绍完大纲视图相关内容之后,接下来,我们会从execute(Params… params)作为入口,重点分析一下AsyncTask的执行流程,我们来看一下execute(Params… params)方法的代码段:

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {  
            if (mStatus != Status.PENDING) {  
                switch (mStatus) {  
                    case RUNNING:  
                        //如果该任务正在被执行则抛出异常  
                        //值得一提的是,在调用cancel取消任务后,状态仍未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)");  
                }  
            }  

            //改变状态为RUNNING  
            mStatus = Status.RUNNING;  

            //调用onPreExecute方法  
            onPreExecute();  

            mWorker.mParams = params;  
            sExecutor.execute(mFuture);  

            return this;  
        }  

三个陌生的变量:mWorker、sExecutor、mFuture,我们也会看一下他们的庐山真面目:

关于sExecutor,它是java.util.concurrent.ThreadPoolExecutor的实例,用于管理线程的执行。代码如下:

    private static final int CORE_POOL_SIZE = 5;  
    private static final int MAXIMUM_POOL_SIZE = 128;  
    private static final int KEEP_ALIVE = 10;  
    //新建一个队列用来存放线程  
       private static final BlockingQueue<Runnable> sWorkQueue =  
               new LinkedBlockingQueue<Runnable>(10);  
    //新建一个线程工厂  
       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 ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,  
               MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);  

mWorker实际上是AsyncTask的一个的抽象内部类的实现对象实例,它实现了Callable接口中的call()方法,代码如下:

 private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {  
        Params[] mParams;  
    } 

而mFuture实际上是java.util.concurrent.FutureTask的实例,下面是它的FutureTask类的相关信息:

  * A cancellable asynchronous computation. 
 * ... 
 */  
public class FutureTask<V> implements RunnableFuture<V> {  }

    public interface RunnableFuture<V> extends Runnable, Future<V> {  
        /** 
         * Sets this Future to the result of its computation 
         * unless it has been cancelled. 
         */  
        void run();  
    }  

可以看到FutureTask是一个可以中途取消的用于异步计算的类。下面是mWorker和mFuture实例在AsyncTask中的体现:

 private final WorkerRunnable<Params, Result> mWorker;  
   private final FutureTask<Result> mFuture;  

public AsyncTask() {  
       mWorker = new WorkerRunnable<Params, Result>() {  
           //call方法被调用后,将设置优先级为后台级别,然后调用AsyncTask的doInBackground方法  
        public Result call() throws Exception {  
               Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
               return doInBackground(mParams);  
           }  
       };  

    //在mFuture实例中,将会调用mWorker做后台任务,完成后会调用done方法  
       mFuture = new FutureTask<Result>(mWorker) {  
           @Override  
           protected void done() {  
               Message message;  
               Result result = null;  

               try {  
                   result = get();  
               } catch (InterruptedException e) {  
                   android.util.Log.w(LOG_TAG, e);  
               } catch (ExecutionException e) {  
                   throw new RuntimeException("An error occured while executing doInBackground()",  
                           e.getCause());  
               } catch (CancellationException e) {  
                //发送取消任务的消息  
                   message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,  
                           new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));  
                   message.sendToTarget();  
                   return;  
               } catch (Throwable t) {  
                   throw new RuntimeException("An error occured while executing "  
                           + "doInBackground()", t);  
               }  

            //发送显示结果的消息  
               message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  
                       new AsyncTaskResult<Result>(AsyncTask.this, result));  
               message.sendToTarget();  
           }  
       };  
   }  

我们看到上面的代码中,mFuture实例对象的done()方法中,如果捕捉到了CancellationException类型的异常,则发送一条“MESSAGE_POST_CANCEL”的消息;如果顺利执行,则发送一条“MESSAGE_POST_RESULT”的消息,而消息都与一个sHandler对象关联。这个sHandler实例实际上是AsyncTask内部类InternalHandler的实例,而InternalHandler正是继承了Handler,下面我们来分析一下它的代码:

    private static final int MESSAGE_POST_RESULT = 0x1; //显示结果  
       private static final int MESSAGE_POST_PROGRESS = 0x2;    //更新进度  
       private static final int MESSAGE_POST_CANCEL = 0x3;  //取消任务  

       private static final InternalHandler sHandler = new InternalHandler();  

    private static class InternalHandler extends Handler {  
           @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})  
           @Override  
           public void handleMessage(Message msg) {  
               AsyncTaskResult result = (AsyncTaskResult) msg.obj;  
               switch (msg.what) {  
                   case MESSAGE_POST_RESULT:  
                       // There is only one result  
                    //调用AsyncTask.finish方法  
                       result.mTask.finish(result.mData[0]);  
                       break;  
                   case MESSAGE_POST_PROGRESS:  
                       //调用AsyncTask.onProgressUpdate方法  
                    result.mTask.onProgressUpdate(result.mData);  
                       break;  
                   case MESSAGE_POST_CANCEL:  
                    //调用AsyncTask.onCancelled方法  
                       result.mTask.onCancelled();  
                       break;  
               }  
           }  
       }  

我们看到,在处理消息时,遇到“MESSAGE_POST_RESULT”时,它会调用AsyncTask中的finish()方法,我们来看一下finish()方法的定义:

    private void finish(Result result) {  
            if (isCancelled()) result = null;  
            onPostExecute(result);  //调用onPostExecute显示结果  
            mStatus = Status.FINISHED;  //改变状态为FINISHED  
        }  

原来finish()方法是负责调用onPostExecute(Result result)方法显示结果并改变任务状态的啊。

概括来说,当我们调用execute(Params… params)方法后,execute方法会调用onPreExecute()方法,然后由ThreadPoolExecutor实例sExecutor执行一个FutureTask任务,这个过程中doInBackground(Params… params)将被调用,如果被开发者覆写的doInBackground(Params… params)方法中调用了publishProgress(Progress… values)方法,则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress… values)方法将被调用;如果遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;如果执行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。

猜你喜欢

转载自blog.csdn.net/qq_28963915/article/details/52105280