• android高级---->AsyncTask的源码分析


      在Android中实现异步任务机制有两种方式,Handler和AsyncTask,它在子线程更新UI的例子可以参见我的博客(android基础---->子线程更新UI)。今天我们通过一个小的案例去深入到AsyncTask的源码,去更好的理解AsyncTask的原理。

    目录导航

    1.  AsyncTask的简要说明
    2.  AsyncTask的的简单的实际案例
    3.  AsyncTask的的源码分析 
    4.  AsyncTask的原理总结
    5.  友情链接

    AsyncTask的简要说明

    一、 AsyncTask的由来背景:

      为了简化Handler的操作,Android1.5提供了工具类android.os.AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。所以它封装了Handler,变得更容易编写。

    二、 AsyncTask是一个抽象的函数,有三个在继承的时候可以指定的参数:,这个后续会讲解原因

    public abstract class AsyncTask<Params, Progress, Result>
    • Params:启动任务执行的输入参数的类型,也就是task.execute()方法中传入的参数类型,doInBackground方法的参数类型也是这个
    • Progress:方便记录后台任务执行的进度,也就是onProgressUpdate和publishProgress方法参数的类型
    • Result:onPostExecute方法参数的类型,也是doInBackground方法返回的类型

    三、 在AsyncTask类的使用过程中,以下的几个方法比较常用的:

    • execute(Params... params):执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
    • onPreExecute():在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前对UI做一些准备工作。
    • doInBackground(Params... params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。doInBackground方法接收的参数就是execute()中传入的参数:另外在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
    • onProgressUpdate(Progress... values),如果调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。否则不执行
    • onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果(就是doInBackground方法返回的结果)将做为参数传递到此方法中,直接将结果显示到UI组件上

    四、 在AsyncTask类的使用技巧,也可以说是使用规范:

    • 异步任务的实例必须在UI线程中创建,而且execute(Params... params)方法必须在UI线程中调用。
    • 一个任务实例只能执行一次,如果执行第二次将会抛出异常。这个将在后续源码解析时说明
    • 不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法
    • 不能在doInBackground(Params... params)中更改UI组件的信息。

    五、 一般使用AsyncTask的场景:

    • schedule messages and runnables to be executed as some point in the future
    • enqueue an action to be performed on a different thread than your own.

    六、 任务的取消

    • 任何时候调用cancel(boolean)方法,都可以取消任务。这个方法会产生的影响是:之后调用的iscancelled()会返回true。
    • 这个方法调用之后,onCancelled(Object)方法会在doInBackground(Object[]) 方法返回后执行,而不是onProgressUpdate(Progress... values)方法
    • 鉴于上述据说,为了确保任务是尽快取消,你应该定期在doInBackground()方法中始终检查iscancelled()方法的返回值。如果可以的话,放在一个循环当中。

    AsyncTask的的实际案例

    了解了上述AsyncTask的基础知识之后,现在我们通过实例去了解AsyncTask的使用和执行流程:

    一、 代码比较简单,在MainActivity的onCreate方法中调用继承MyAsynTask类的execute()方法:以下是全部代码

    package com.example.linux.asyntasktest;
    
    import android.os.AsyncTask;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.TextView;
    
    /**
    * writer: huhx
    */
    public class MainActivity extends AppCompatActivity { private final static String TAG = "MainActivity"; private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); } // asynTask的使用 public void asynTask(View view) { MyAsynTask myAsynTask = new MyAsynTask(); myAsynTask.execute("huhx"); } // MyAsynTask内部类 private class MyAsynTask extends AsyncTask<String, Integer, String> { private final static String TAG = "MyHuhxAsynTask"; public MyAsynTask() { Log.i(TAG, "胡红翔 constructor"); } @Override protected String doInBackground(String... params) { Log.i(TAG, "params: " + params[0]); publishProgress(13); return "world"; } @Override protected void onPostExecute(String s) { textView.setText(s); Log.i(TAG, "on post execute string: " + s); } @Override protected void onPreExecute() { super.onPreExecute(); Log.i(TAG, "on pre execute."); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); Log.i(TAG, "on progress update : " + values[0]); } } }

    二、 我们大致看一下执行的流程,执行的日志结果如下:

    03-19 19:22:03.557 6442-6442/com.example.linux.asyntasktest I/MyHuhxAsynTask: 胡红翔 constructor
    03-19 19:22:03.557 6442-6442/com.example.linux.asyntasktest I/MyHuhxAsynTask: on pre execute.
    03-19 19:22:03.567 6442-7172/com.example.linux.asyntasktest I/MyHuhxAsynTask: params: huhx
    03-19 19:22:03.587 6442-6442/com.example.linux.asyntasktest I/MyHuhxAsynTask: on progress update : 13
    03-19 19:22:03.587 6442-6442/com.example.linux.asyntasktest I/MyHuhxAsynTask: on post execute string: world

    三、 从以上打印的日志,我们初步得到AsyncTask的执行流程:

    • 首先执行MyAsynTask的构造方法,然后执行onPostExecute方法。
    • 执行doInBackground方法,并且该方法的参数就是execute方法传递过来的参数
    • 由于doInBackground中定义了publishProgress方法,onProgressUpdate方法接接着执行,并且该方法的的参数就是publishProgress方法传递过来的参数
    • 最后onPostExecute方法得到执行,并且该方法的参数就是doInBackground方法return的值

    AsyncTask的的源码分析

     好了,上述我们基本得到了AsyncTask的执行流程,现在我们通过源码并且结合上述案例,对AsyncTask做更为细致的分析:

    一、 首先我们是在主线程上创建了一个继承AsyncTask的MyAsynTask类: MyAsynTask myAsynTask = new MyAsynTask();由于是继承关系,上述方法执行了MyAsynTask的父类AsyncTask的构造方法:

    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
    
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };
    
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }
    • AsyncTask类初始化了两个类:mWorker 与mFuture:
    • WorkerRunnable是实现了Callable接口的抽象方法;FutureTask实现了RunnableFuture,而RunnableFuture接口继承了Runnable和Future
    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> 
    public interface RunnableFuture<V> extends Runnable, Future<V>
    public class FutureTask<V> implements RunnableFuture<V>

    二、 调用myAsynTask对象的execute()方法,并且传递参数huhx;我们跟进去,发现实际的执行是:executeOnExecutor(sDefaultExecutor, params);

    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;
    }
    • 该方法首先是判断mStatus状态,如果是正在运行(RUNNING)或者已经结束运行(FINISHED),就会抛出异常。
    • 接着设置状态为运行,执行onPreExecute()方法,并把参数的值赋给mWorker.mParams;
    • 于是Executor去执行execute的方法,学过java多线程的都知道。这个方法是开启一个线程去执行mFuture中的run()方法
    • 注意mFuture和mWorker都是在AsyncTask的构造方法中初始化过的

    三、 我们接着上述的讲解,说是mFuture的run方法执行:于是,我们跟进去:

    public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

    四、 上述有一句重要的代码:发现里面重要的代码:result = c.call(),这个call方法,就是执行了在AsyncTask构造方法中mWorker的call方法:这里我们说一下原因:

      1.  mFuture = new FutureTask<Result>(mWorker),将mWorker当作参数传递给FutureTask的构造函数

      2. 而FutureTask的构造函数如下:所以c.call()就是执行了mWorker中的call()方法

    public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            this.callable = callable;
            this.state = NEW;       // ensure visibility of callable
        }

    五、 上述我们的执行流程来到了mWorker的call方法:为了方便,我们把它复制过来:如下

    public Result call() throws Exception {
        mTaskInvoked.set(true);
    
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //noinspection unchecked
        Result result = doInBackground(mParams);
        Binder.flushPendingCommands();
        return postResult(result);
    }
    • 设置最高优先级,接着执行了doInBackground()方法,注意它的参数mParams正是mWorker的属性mParams,而我们在之前有过这样的代码:mWorker.mParams = params;因此doInBackground方法的参数就是execute方法传递的参数
    • 好了,执行到了我们重写的doInBackground()方法了,现在要回到MyAsynTask类中的来了,在doInBackground中执行了publishProgress方法。跟进去,我们看一下代码
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

    六、 上述我们讲到了Handler的部分了,很自然的我们是不是要看一下Handler的handleMessage方法呢?跟进去,我们看一下

    public void handleMessage(Message msg) {
        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch (msg.what) {
            case MESSAGE_POST_RESULT:
                // There is only one result
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
    • 由于上述传递的消息是MESSAGE_POST_PROGRESS,所以result.mTask.onProgressUpdate(result.mData);得到执行,那么result.mTas是什么了,对了,就是我们的AsyncTask。由于AsyncTaskResult的第二个参数是values是publishProgress的参数,那么onProgressUpdate中的参数就是publishProgress方法的参数如下!
      private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;
    
        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

    七、 好了,我们要回到第五步的,最后一个postResult(result)方法了,在这个方法当中,如下

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    • 看到没有,发送了MESSAGE_POST_RESULT信息,于是在第六步中的handleMessage方法的代码中result.mTask.finish(result.mData[0])得到执行,在这个方法中,执行了AsyncTask的finish方法
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
    • 在这代码中,如果没有取消,那么就执行onPostExecute方法,记得result是什么吗?Result result = doInBackground(mParams);正是doInBackground方法返回的结果
    • 最后将状态设置为Status.FINISHED,还记得我们在AsyncTask的简要说明的第四点说过吗?一个任务实例只能执行一次,如果执行第二次将会抛出异常,因为执行完一次之后,状态变成FINISHED,在executeOnExecutor方法中会有如下判断:会报异常的!
    case FINISHED:
            throw new IllegalStateException("Cannot execute task:"
                    + " the task has already been executed "
                    + "(a task can be executed only once)");
    }

    八、 对于在任务的取消中那些说明,我们额外去对它的源码做一些简单的分析:

    • 调用onCancelled(true)时,系统会发送MESSAGE_POST_RESULT信息,也就是提前进入了上述第七步:执行如下代码
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
    • 由于设置了onCancelled(true),所以onCancelled(result)方法得到执行。之后再设置状态为Status.FINISHED;

    AsyncTask的原理总结

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

    友情链接 -- huhx

  • 相关阅读:
    收银钱箱弹出设置
    IOS4.0 实例练习时钟
    mysql 日期查询操作 copy
    ios 学习笔记 2
    SVN 不能移动 xx\entries 到 xx\entries
    做一个基于PHPCMS V9架构的商城
    基于JDBC API 的事务管理代码示例
    mysql 数据类型
    Discuz!NT CreditsOperationType
    spring 事务传播行为
  • 原文地址:https://www.cnblogs.com/huhx/p/asynctask_theory.html
Copyright © 2020-2023  润新知