zoukankan      html  css  js  c++  java
  • 第十一章 Android的线程和线程池

    AsyncTask

    1. 三个参数(都可为Void):
      Params:参数
      Progress:执行进度
      Result:返回值
    2. 四个方法 :
      onPreExecute() 主线程执行,异步方法执行前调用。
      doInBackground(Params...params) 线程池中执行,用于执行异步任务;在方法内部用publishProgress 来更新任务进度。
      onProgressUpdate(Progress...value)主线程执行,后台任务进度状态改变时被调用。
      onPostExecute(Result result) 主线程执行,异步任务执行之后被调用
      执行顺序: onPreExecute->doInBackground->onPostExecute 如果取消了异步任务,会回调onCancelled(),onPostExecute则不会被调用

    Tips: AsyncTask的类必须在主线程加载,Android4.1及以上已经被系统自动完成了;AsyncTask对象必须在主线程创建;execute方法需要在UI线程调用;一个AsyncTask对象只能调用一次;Android1.6之前串行执行,Android1.6采用线程池并行处理任务,Android3.0开始,采用一个线程执行任务,但也可以通过executeOnExecutor方法来并行执行任务




    AsyncTask的工作原理

  • AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个InternalHandler,其中线程池SerialExecutor用于任务排队,THREAD_POOL_EXECUTOR用于真正执行任务,InternalHandler用于将执行环境切换到主线程

  • AsyncTask的排队过程:系统首先会把AsyncTask的Params参数封装成FutureTask对象,它充当Runnable的作用,接下来这个FutureTask会交给SerialExecutor的execute方法处理,execute方法首先会把FutereTask对象插入到任务队列mTasks中去;如果没有正在活动的AsyncTask任务,就会执行下一个AsyncTask任务;同时当一个AsyncTask任务执行完成后,AsyncTask会继续执行其他任务直到所有任务都执行为止,可以看出默认情况,AsyncTask是串行执行的(Android3.0后)

先看一段示例:

    

  1. package com.example.zhy_asynctask_demo01;
  2. import android.app.Activity;
  3. import android.app.ProgressDialog;
  4. import android.os.AsyncTask;
  5. import android.os.Bundle;
  6. import android.util.Log;
  7. import android.widget.TextView;
  8. public class MainActivity extends Activity
  9. {
  10. private static final String TAG = "MainActivity";
  11. private ProgressDialog mDialog;
  12. private TextView mTextView;
  13. @Override
  14. protected void onCreate(Bundle savedInstanceState)
  15. {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18. mTextView = (TextView) findViewById(R.id.id_tv);
  19. mDialog = new ProgressDialog(this);
  20. mDialog.setMax(100);
  21. mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  22. mDialog.setCancelable(false);
  23. new MyAsyncTask().execute();
  24. }
  25. private class MyAsyncTask extends AsyncTask<Void, Integer, Void>
  26. {
  27. @Override
  28. protected void onPreExecute()
  29. {
  30. mDialog.show();
  31. Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
  32. }
  33. @Override
  34. protected Void doInBackground(Void... params)
  35. {
  36. // 模拟数据的加载,耗时的任务
  37. for (int i = 0; i < 100; i++)
  38. {
  39. try
  40. {
  41. Thread.sleep(80);
  42. } catch (InterruptedException e)
  43. {
  44. e.printStackTrace();
  45. }
  46. publishProgress(i);
  47. }
  48. Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
  49. return null;
  50. }
  51. @Override
  52. protected void onProgressUpdate(Integer... values)
  53. {
  54. mDialog.setProgress(values[0]);
  55. Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
  56. }
  57. @Override
  58. protected void onPostExecute(Void result)
  59. {
  60. // 进行数据加载完成后的UI操作
  61. mDialog.dismiss();
  62. mTextView.setText("LOAD DATA SUCCESS ");
  63. Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
  64. }
  65. }
  66. }

进入某个Activity,Activity中需要的数据来自于网络或者其它耗时操作,可以在AsyncTask中onPreExecute完成一些准备操作,比如上例中显示进度对话框;然后在doInBackground完成耗时操作,在进行耗时操作时还能不时的通过publishProgress给onProgressUpdate中传递参数,然后在onProgressUpdate中可以进行UI操作,比如上例更新进度条的进度;当耗时任务执行完成后,最后在onPostExecute进行设置控件数据更新UI等操作,例如隐藏进度对话框。



源码解析

注:本篇源码分析基于Andorid-17,因为和3.0之前版本变动较大,有必要标出。

那么大家一定好奇,AsyncTask在Android中是如何实现的,下面进行源码分析:从我们的执行异步任务的起点开始,进入execute方法:

  1. public final AsyncTask<Params, Progress, Result> execute(Params... params) {
  2. return executeOnExecutor(sDefaultExecutor, params);
  3. }
  4. public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
  5. Params... params) {
  6. if (mStatus != Status.PENDING) {
  7. switch (mStatus) {
  8. case RUNNING:
  9. throw new IllegalStateException("Cannot execute task:"
  10. + " the task is already running.");
  11. case FINISHED:
  12. throw new IllegalStateException("Cannot execute task:"
  13. + " the task has already been executed "
  14. + "(a task can be executed only once)");
  15. }
  16. }
  17. mStatus = Status.RUNNING;
  18. onPreExecute();
  19. mWorker.mParams = params;
  20. exec.execute(mFuture);
  21. return this;
  22. }

18行:设置当前AsyncTask的状态为RUNNING,上面的switch也可以看出,每个异步任务在完成前只能执行一次。
20行:执行了onPreExecute(),当前依然在UI线程,所以我们可以在其中做一些准备工作。
22行:将我们传入的参数赋值给了mWorker.mParams
23行:exec.execute(mFuture)

相信大家对22行出现的mWorker,以及23行出现的mFuture都会有些困惑。
mWorker找到这个类:

  1. private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
  2. Params[] mParams;
  3. }
可以看到是Callable的子类,且包含一个mParams用于保存我们传入的参数,下面看初始化mWorker的代码:
  1. public AsyncTask() {
  2. mWorker = new WorkerRunnable<Params, Result>() {
  3. public Result call() throws Exception {
  4. mTaskInvoked.set(true);
  5. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  6. //noinspection unchecked
  7. return postResult(doInBackground(mParams));
  8. }
  9. };
  10. //….
  11. }
可以看到mWorker在构造方法中完成了初始化,并且因为是一个抽象类,在这里new了一个实现类,实现了call方法,call方法中设置mTaskInvoked=true,且最终调用doInBackground(mParams)方法,并返回Result值作为参数给postResult方法.可以看到我们的doInBackground出现了,下面继续看:
  1. private Result postResult(Result result) {
  2. @SuppressWarnings("unchecked")
  3. Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
  4. new AsyncTaskResult<Result>(this, result));
  5. message.sendToTarget();
  6. return result;
  7. }
可以看到postResult中出现了我们熟悉的异步消息机制,传递了一个消息message, message.what为MESSAGE_POST_RESULT;
message.object= new AsyncTaskResult(this,result);
  1. private static class AsyncTaskResult<Data> {
  2. final AsyncTask mTask;
  3. final Data[] mData;
  4. AsyncTaskResult(AsyncTask task, Data... data) {
  5. mTask = task;
  6. mData = data;
  7. }
  8. }
AsyncTaskResult就是一个简单的携带参数的对象。

看到这,我相信大家肯定会想到,在某处肯定存在一个sHandler,且复写了其handleMessage方法等待消息的传入,以及消息的处理。


  1. private static final InternalHandler sHandler = new InternalHandler();
  2. private static class InternalHandler extends Handler {
  3. @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
  4. @Override
  5. public void handleMessage(Message msg) {
  6. AsyncTaskResult result = (AsyncTaskResult) msg.obj;
  7. switch (msg.what) {
  8. case MESSAGE_POST_RESULT:
  9. // There is only one result
  10. result.mTask.finish(result.mData[0]);
  11. break;
  12. case MESSAGE_POST_PROGRESS:
  13. result.mTask.onProgressUpdate(result.mData);
  14. break;
  15. }
  16. }
  17. }
哈哈,出现了我们的handleMessage,可以看到,在接收到MESSAGE_POST_RESULT消息时,执行了result.mTask.finish(result.mData[0]);其实就是我们的AsyncTask.this.finish(result),于是看finish方法
  1. private void finish(Result result) {
  2. if (isCancelled()) {
  3. onCancelled(result);
  4. } else {
  5. onPostExecute(result);
  6. }
  7. mStatus = Status.FINISHED;
  8. }
可以看到,如果我们调用了cancel()则执行onCancelled回调;正常执行的情况下调用我们的onPostExecute(result);主要这里的调用是在handler的handleMessage中,所以是在UI线程中。

最后将状态置为FINISHED。

mWoker看完了,应该到我们的mFuture了,依然实在构造方法中完成mFuture的初始化,将mWorker作为参数,复写了其done方法。

  1. public AsyncTask() {
  2. ...
  3. mFuture = new FutureTask<Result>(mWorker) {
  4. @Override
  5. protected void done() {
  6. try {
  7. postResultIfNotInvoked(get());
  8. } catch (InterruptedException e) {
  9. android.util.Log.w(LOG_TAG, e);
  10. } catch (ExecutionException e) {
  11. throw new RuntimeException("An error occured while executing doInBackground()",
  12. e.getCause());
  13. } catch (CancellationException e) {
  14. postResultIfNotInvoked(null);
  15. }
  16. }
  17. };
  18. }
任务执行结束会调用:postResultIfNotInvoked(get());get()表示获取mWorker的call的返回值,即Result.然后看postResultIfNotInvoked方法

  1. private void postResultIfNotInvoked(Result result) {
  2. final boolean wasTaskInvoked = mTaskInvoked.get();
  3. if (!wasTaskInvoked) {
  4. postResult(result);
  5. }
  6. }
如果mTaskInvoked不为true,则执行postResult;但是在mWorker初始化时就已经将mTaskInvoked为true,所以一般这个postResult执行不到。
好了,到了这里,已经介绍完了execute方法中出现了mWorker和mFurture,不过这里一直是初始化这两个对象的代码,并没有真正的执行。下面我们看真正调用执行的地方。
execute方法中的:
还记得上面的execute中的23行:exec.execute(mFuture)

exec为executeOnExecutor(sDefaultExecutor, params)中的sDefaultExecutor

下面看这个sDefaultExecutor
  1. private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
  2. public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
  3. private static class SerialExecutor implements Executor {
  4. final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
  5. Runnable mActive;
  6. public synchronized void execute(final Runnable r) {
  7. mTasks.offer(new Runnable() {
  8. public void run() {
  9. try {
  10. r.run();
  11. } finally {
  12. scheduleNext();
  13. }
  14. }
  15. });
  16. if (mActive == null) {
  17. scheduleNext();
  18. }
  19. }
  20. protected synchronized void scheduleNext() {
  21. if ((mActive = mTasks.poll()) != null) {
  22. THREAD_POOL_EXECUTOR.execute(mActive);
  23. }
  24. }
  25. }

可以看到sDefaultExecutor其实为SerialExecutor的一个实例,其内部维持一个任务队列;直接看其execute(Runnable runnable)方法,将runnable放入mTasks队尾;
16-17行:判断当前mActive是否为空,为空则调用scheduleNext方法
20行:scheduleNext,则直接取出任务队列中的队首任务,如果不为null则传入THREAD_POOL_EXECUTOR进行执行。
下面看THREAD_POOL_EXECUTOR为何方神圣:
  1. public static final Executor THREAD_POOL_EXECUTOR
  2. =new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
  3. TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到就是一个自己设置参数的线程池,参数为:
  1. //现在已经根据CPU内核数目来设置线程池的大小了.

  1. private static final int CORE_POOL_SIZE = 5;
  2. private static final int MAXIMUM_POOL_SIZE = 128;
  3. private static final int KEEP_ALIVE = 1;
  4. private static final ThreadFactory sThreadFactory = new ThreadFactory() {
  5. private final AtomicInteger mCount = new AtomicInteger(1);
  6. public Thread newThread(Runnable r) {
  7. return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
  8. }
  9. };
  10. private static final BlockingQueue<Runnable> sPoolWorkQueue =
  11. new LinkedBlockingQueue<Runnable>(10);
可以看到,如果此时有10个任务同时调用execute(s synchronized)方法,第一个任务入队,然后在mActive = mTasks.poll()) != null被取出,并且赋值给mActivte,然后交给线程池去执行。然后第二个任务入队,但是此时mActive并不为null,并不会执行scheduleNext();所以如果第一个任务比较慢,10个任务都会进入队列等待;真正执行下一个任务的时机是,线程池执行完成第一个任务以后,调用Runnable中的finally代码块中的scheduleNext,所以虽然内部有一个线程池,其实调用的过程还是线性的。一个接着一个的执行,相当于单线程。



 HandlerThread

  • HandlerThread继承了Thread,是一种可以使用Handler的Thread;在run方法中通过looper.prepare()来开启消息循环,这样就可以在HandlerThread中创建Handler了;外界可以通过一个Handler的消息方式来通知HandlerThread来执行具体任务;确定不使用之后,可以通过quit或quitSafely方法来终止线程执行;具体使用场景是IntentService。

2.4 IntentService

  1. IntentSercie是一种特殊的Service,继承了Service并且是抽象类,任务执行完成后会自动停止,优先级远高于普通线程,适合执行一些高优先级的后台任务;
  2. IntentService封装了HandlerThread和Handler,onCreate方法自动创建一个HandlerThread,然后用它的Looper构造了一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息都会在HandlerThread执行;
    IntentServiced的onHandlerIntent方法是一个抽象方法,需要在子类实现,onHandlerIntent方法执行后,stopSelt(int startId)就会停止服务,如果存在多个后台任务,执行完最后一个stopSelf(int startId)才会停止服务















来自为知笔记(Wiz)


查看全文
  • 相关阅读:
    UVA 11174 Stand in a Line,UVA 1436 Counting heaps —— (组合数的好题)
    UVA 1393 Highways,UVA 12075 Counting Triangles —— (组合数,dp)
    【Same Tree】cpp
    【Recover Binary Search Tree】cpp
    【Binary Tree Zigzag Level Order Traversal】cpp
    【Binary Tree Level Order Traversal II 】cpp
    【Binary Tree Level Order Traversal】cpp
    【Binary Tree Post order Traversal】cpp
    【Binary Tree Inorder Traversal】cpp
    【Binary Tree Preorder Traversal】cpp
  • 原文地址:https://www.cnblogs.com/You0/p/5984482.html
  • Copyright © 2011-2022 走看看