Android5.0 AsyncTask的实现分析

来源:互联网 发布:我国网络零售的特点 编辑:程序博客网 时间:2024/06/05 06:25

首先看一下AsyncTask在Android中的一个简单应用:

package com.example.zhy_asynctask_demo01;  import android.app.Activity;  import android.app.ProgressDialog;  import android.os.AsyncTask;  import android.os.Bundle;  import android.util.Log;  import android.widget.TextView;  public class MainActivity extends Activity  {      private static final String TAG = "MainActivity";      private ProgressDialog mDialog;      private TextView mTextView;      @Override      protected void onCreate(Bundle savedInstanceState)      {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          mTextView = (TextView) findViewById(R.id.id_tv);          mDialog = new ProgressDialog(this);          mDialog.setMax(100);          mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);          mDialog.setCancelable(false);          new MyAsyncTask().execute();      }      private class MyAsyncTask extends AsyncTask<Void, Integer, Void>      {          @Override          protected void onPreExecute()          {              mDialog.show();              Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");          }          @Override          protected Void doInBackground(Void... params)          {              // 模拟数据的加载,耗时的任务              for (int i = 0; i < 100; i++)              {                  try                  {                      Thread.sleep(80);                  } catch (InterruptedException e)                  {                      e.printStackTrace();                  }                  publishProgress(i);              }              Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");              return null;          }          @Override          protected void onProgressUpdate(Integer... values)          {              mDialog.setProgress(values[0]);              Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");          }          @Override          protected void onPostExecute(Void result)          {              // 进行数据加载完成后的UI操作              mDialog.dismiss();              mTextView.setText("LOAD DATA SUCCESS ");              Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");          }      }  }  

在这个简单的Demo中我们可以看到 AsyncTask的入口在:

new MyAsyncTask().execute(); 

进入到源码中我们看下execute()方法:

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }

在函数中又调用了executeOnExecutor方法:

    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;    }

方法中根据一个枚举来判定AsyncTask的当前的状态:

    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,    }
  • PENDING:还未执行过executed
  • RUNNING:正在执行过程中
  • FINISHED:已经结束
    在executeOnExecutor中每个异步任务在完成前只能执行一次,通过上述的枚举类型中的状态实现,随后调用的是onPreExecute()方法:
    protected void onPreExecute() {    }

这里还是在主线程中,我们可以重写这个方法,做一些开始异步操作前的一些准备动作。
执行完成后:

mWorker.mParams = params;

在Asytask中有两个重要的成员变量:

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

我们可以将这里的mWorker 视为一个Runable接口 这里将参数Parameter 传入到mWorker 中
接下来执行:

exec.execute(mFuture);

我们研究下这里的exec 变量:
它的传入参数是一个成员变量: sDefaultExecutor 来看下如何定义的:

private static class SerialExecutor implements Executor {        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();        Runnable mActive;        public synchronized void execute(final Runnable r) {            mTasks.offer(new Runnable() {                public void run() {                    try {                        r.run();                    } finally {                        scheduleNext();                    }                }            });            if (mActive == null) {                scheduleNext();            }        }        protected synchronized void scheduleNext() {            if ((mActive = mTasks.poll()) != null) {                THREAD_POOL_EXECUTOR.execute(mActive);            }        }    }

最终先开始调用的excute方法就是执行这个内部类中的excute方法:
这个方法同时也是AsyTask的精髓:
在内部类中有一个成员变量:

final ArrayDeque<Runnable> mTasks

我们介绍下这个:
1)ArrayDeque有两个类属性,head和tail,两个指针。
2)ArrayDeque通过一个数组作为载体,其中的数组元素在add等方法执行时不移动,发生变化的只是head和tail指针,而且指针是循环变化,数组容量不限制。
3)offer方法和add方法都是通过其中的addLast方法实现,每添加一个元素,就把元素加到数组的尾部,此时,head指针没有变化,而tail指针加一,因为指针是循环加的,所以当tail追上head((this.tail = this.tail + 1 & this.elements.length - 1) == this.head)时,数组容量翻一倍,继续执行。
4)remove方法和poll方法都是通过其中的pollFirst方法实现,每移除一个元素,该元素所在位置变成null,此时,tail指针没有变化,而head指针加一,当数组中没有数据时,返回null。
5)因为ArrayDeque不是线程安全的,所以,用作堆栈时快于 Stack,在用作队列时快于 LinkedList。
其实说明白了它就是一个队列,里面的offer 方法就是将请求缓存起来,poll方法用来获取一个请求,我们知道在之前的版本中AsyTask被人诟病的就是当请求数超过128后 会抛出异常,但是在新版本的AsyTask中我们用队列将请求缓存后便不存在这种风险,实际上最终excute方法会调用到的方法是 mFuture中的run方法:

    public void run() {        if (state != NEW ||            !UNSAFE.compareAndSwapObject(this, runnerOffset,                                         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);        }    }

方法中我们可以看到最终是调用到的callable 的call方法这里的callable就是两个重要的成员变量的第二个:mWorker中的call:

            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                return postResult(doInBackground(mParams));            }         

这里调用到了doInBackground(mParams) 进行耗时操作

其实总结起来AsyTask就是线程池和Handler的一个封装

0 0
原创粉丝点击