AsyncTask学习笔记

1)AsyncTask 用法

public abstract class AsyncTask<Params, Progress, Result> {
         .....................
}
 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long>; {
      protected Long doInBackground(URL... urls) {
          int count = urls.length;
          long totalSize = 0;
          for (int i = 0; i < count; i++) {
              totalSize += Downloader.downloadFile(urls[i]);
              publishProgress((int) ((i / (float) count) * 100));
              // Escape early if cancel() is called
              if (isCancelled()) break;
          }
          return totalSize;
      }

     protected void onProgressUpdate(Integer... progress) {
          setProgressPercent(progress[0]);
      }

      protected void onPostExecute(Long result) {
          showDialog("Downloaded " + result + " bytes");
      }
  }

由上述代码可知,AsyncTask是抽象类,需要类去继承并且子类需要指定3个泛型,它们分别对应doInBackground(),onProgressUpdate(),onPostExecute()的参数类型。它的核心方法:onPreExecute(),doInBackground(),onProgressUpdate(),onPostExecute(),publishProgress(),
这其中只有doInBackground()是在子线程执行,其余都在主线程中执行。

2)执行的顺序:
onPreExecute()–>doInBackground()–>publishProgress()onProgressUpdate()–>onPostExecute()

  1. onPreExecute()
    这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
  2. doInBackground(Params…)
    这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress…)方法来完成。
  3. onProgressUpdate(Progress…)
    当在后台任务中调用了publishProgress(Progress…)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
  4. onPostExecute(Result)
    当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。

3)AsyncTask 源码分析
1.从execute()开始:

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

调用了executeOnExecutor(sDefaultExecutor, params)方法。

2.executeOnExecutor(sDefaultExecutor, params)

 @MainThread
    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是什么?
        *mFuture是什么?runnable?
        */
        exec.execute(mFuture);
        return this;
    }

由上可知,当前任务状态为RUNNING时,再次调用executeOnExecutor()会抛出IllegalStateException(“当前任务已经在执行”),当前任务状态为时FINISHED时,同样会抛出IllegalStateException异常,因为在AsyncTask中一个任务只能执行一次即使执行过程中被cancell掉 往下看调用了onPreExecute(),然后mWorker,mFuture是什么?先不管,再往后 exec.execute(mFuture),终于执行任务了。

3.exec是什么?
exec是我们传进来的sDefaultExecutor,那么sDefaultExecutor是什么?

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

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

到这可以得知sDefaultExecutor 其实是一个SerialExecutor 对象,调用它的execute(Runnable r)方法的时候,会调用ArrayDeque的offer()方法将传入的Runnable对象添加到队列的尾部,然后判断mActive对象是不是等于null,第一次运行当然是等于null了,于是会调用scheduleNext()方法。在这个方法中ArrayDeque的poll()会从队列的头部取值,并赋值给mActive对象,然后调用THREAD_POOL_EXECUTOR去执行取出的取出的Runnable对象。之后如何又有新的任务被执行,同样还会调用offer()方法将传入的Runnable添加到队列的尾部,但是再去给mActive对象做非空检查的时候就会发现mActive对象已经不再是null了,于是就不会再调用scheduleNext()方法。而是在finally语句块中调用了scheduleNext()方法。SerialExecutor 作用是让线程池严格的按照任务添加的顺序执行,一个结束,一个开始。

4.mFuture,mWorker是什么?

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

mFuture 是一个FutureTask对象,实现了RunnableFuture接口,mWorker 是一个WorkerRunnable对象,实现了Callable接口。

FutureTask类:

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

现在来看FutureTask的run()方法

public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
        //c就是传入的mWorker 
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                //执行mWorker的call()方法
                    result = c.call();
                //将ran设置为true
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                //ran为true执行set(result);
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

由上可知在FutureTask的run()方法中调用了mWorker的call()方法,现在我们来看mWorker的run()

 mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                 ........
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };

doInBackground()方法被调用,再由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;
    }
    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

     private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

        @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
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
//   onProgressUpdate在此调用               result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

@WorkerThread
protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {  getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

这段代码就是一个handler发送消息和接收消息的过程。
当msg.what==MESSAGE_POST_PROGRESS时,调用onProgressUpdate()方法,信息源是来自publishProgress()方法,正因如此,在doInBackground()方法中调用publishProgress()方法才可以从子线程切换到UI线程,从而完成对UI元素的更新操作
当MESSAGE_POST_RESULT时, result.mTask就是AsyncTask,调用他的finish()方法,在这里调用了 onPostExecute(result)。

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

到这mWorker 的run()执行完了,那么mFuture 的done()什么时候执行?回到FutureTask.run()方法,

   //ran为true执行set(result);
    if (ran)  set(result);

mFuture 的 set(result);

    protected void set(V v) {
        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
            outcome = v;
            U.putOrderedInt(this, STATE, NORMAL); // final state
            //注意这里
            finishCompletion();
        }
    }
   private void finishCompletion() {
       ..............此处省略
       //执行done()
          done();
       ..............此处省略
    }

4)AsyncTask缺陷与解决
1.AsyncTask类包含一个全局静态的线程池THREAD_POOL_EXECUTOR,线程池的配置参数如下:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

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 BlockingQueue<Runnable>sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
public static final Executor THREAD_POOL_EXECUTOR = 
new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

当线程池中已有线程个数达到MAXIMUM_POOL_SIZE ,并且缓冲队列已满,如果此时在向线程提交任务,将会抛出RejectedExecutionException

解决方案:替换默认的RejectedExecutionHandler使用
ThreadPoolExecutor.DiscardOldestPolicy()代替。
在调用executeOnExecutor替换线程池。
注意:根据需求合理的选择和设置线程池。

 private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,             MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());
  public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public DiscardOldestPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
}

2.AsyncTask与他所在的activity 的生命周期不是一致的,activity 终止,AsyncTask并不会终止,它会以它自有的方式继续运行,即使你退出了整个应用程序,AsyncTask提前结束的唯一方法是通过调用AsyncTask.cancel()进行取消。由于不必要的后台线程会导致app阻塞的风险,或者内存泄露。当不再需要一个AsyncTask时,一定要取消它,防止在app执行期间引起任何问题。
而且即使调用了cancel() , 也未必能真正地取消任务。因为如果在doInBackgroud里有一个不可中断的操作,比如BitmapFactory.decodeStream(),那么这个操作会继续下去。
3.AsyncTask内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。

非静态内部类或非静态匿名类会隐式的持有外部类的引用,外部类就有可能发生泄漏。

4.屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

5)AsyncTask使用注意事项
1.Task的实例必须在UI thread中创建。

/* Creates a new asynchronous task. This constructor must be *invoked on the UI thread. */
    public AsyncTask() {
         ........省略
}

2.. execute方法必须在UI thread中调用 。( @MainThread修饰的方法必须在主线程调用)

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

3.不要手动的去调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法 .
4. 一个AsyncTask对象只能执行一次,否则会有异常抛出”java.lang.IllegalStateException: Cannot execute task: the task is already running”。
5. doInBackground()方法并不是在onPreExecute()方法做完全部操作才开始执行。

参考:http://blog.csdn.net/hitlion2008/article/details/7983449

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值