博客主页

前面分析完了Handler源码,但是还有很多不为人知的秘密,接下来分析它。

涉及到的类:
HandlerThread、IntentService、AsyncTask、Messenger、IdleHandler、Looper.Observer、MessageLogging等

上半部分讲解内容:HandlerThread、IntentService、AsyncTask
下半部分讲解内容:Messenger、IdleHandler、Looper.Observer、MessageLogging

1. HandlerThread

背景:在Android系统中使用消息机制进行线程间的消息传递。如果要在子线程中传递消息,就需要创建一个子线程的Handler。

    new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();

            Handler workHandler = new Handler(new Handler.Callback() {
                @Override
                public boolean handleMessage(@NonNull Message msg) {
                    // 处理子线程的消息
                    return false;
                }
            });

            // 发送消息
            workHandler.sendEmptyMessage(0);

            Looper.loop();
        }
    }).start();

这种方式虽然可以实现在子线程中进行消息的传递,但很麻烦且该子线程不能退出循环。Android为我们提供了很好的组件HandlerThread。

查看源码发现,HandlerThread是继承Thread,在内部维护一个Looper,当线程开启后run方法运行起来,就会创建一个Looper。定义如下:

/**
 * A {@link Thread} that has a {@link Looper}.
 * The {@link Looper} can then be used to create {@link Handler}s.
 * <p>
 * Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
 */
public class HandlerThread extends Thread {}

它的主要作用:处理单线程的耗时任务。

1.1 基本使用

创建HandlerThread(需要指定线程的名字)后,必须先启动HandlerThread线程。

HandlerThread handlerThread = new HandlerThread("AsyncThreadTask");
handlerThread.start(); // 启动线程

// 创建Handler时需要指定HanderThread中创建的Looper对象
Handler workHandler = new Handler(handlerThread.getLooper());

// 发送消息
workHandler.post(new Runnable() {
    @Override
    public void run() {
      // 处理耗时任务
    }
});

// 退出消息循环,发送的消息就不会被处理了
handlerThread.quit();

1.2 源码解析

HandlerThread的源码很简单只有100多行,先来看下它的构造方法

// HandlerThreadde.java源码

   int mPriority; // 线程优先级
   public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

构造方法参数有两个:

  • name 线程的名字
  • priority 线程的优先级

线程start()后run方法执行,当前线程绑定Looper对象,并循环该线程中的消息。

// HandlerThreadde.java源码

    Looper mLooper; // 当前线程持有的Looper对象

    // Looper已经创建完成调用
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare(); // 创建Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll(); // 唤醒等待的线程
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop(); // 
        mTid = -1;
    }

提供了获取当前线程的Looper的方法。

// HandlerThreadde.java源码

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

如果当前线程没有运行,直接返回null;如果当前线程已经运行,但Looper还没有创建完成,则wait,等待Looper创建完成,否则直接返回该线程的Looper对象。

2. IntentService

背景:在Android应用的程序中,如果Service中处理耗时的操作,很容易出现ANR的现象,通常的做法就是,在onStartCommon方法中开启一个子线程然后内部执行耗时的操作,在执行完毕后如果停止服务,还需要手动的在子线程的run方法中调用stopSelf()来停止服务。

其实IntentService,就是Service 和 HandlerThread 的结合体。

IntentService定义的三个基本点:是什么?怎么用?如何work?

/**
  1、是什么?
    IntentService is a base class for {@link Service}s that 
      handle asynchronous requests (expressed as {@link Intent}s) on demand. 

 2、怎么用?
  Clients send requests through 
   {@link android.content.Context#startService(Intent)} calls; 

 3、如何work?
   the service is started as needed, handles each Intent 
   in turn using a worker thread, and stops itself when it runs out of work.
 */
public abstract class IntentService extends Service {}

1、IntentService特点

  • IntentService是Service类的子类,用来处理异步请求
  • IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue单链表的形式
  • 由于是单线程(一个工作线程),所以所有的任务需要排队执行

2、 IntentService的优点和缺点

IntentService相对与Service的好处:

  • 使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
  • 当操作完成时,我们不用手动停止Service

但是它的缺点也显而易见:

  • 由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况
  • 不适合用于bindService()这样的启动方式的

2.1 简单使用

1、IntentService是一个抽象类,内部有一个抽象方法onHandleIntent。

public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.d(TAG, "onHandleIntent: " + Thread.currentThread().getName());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

2、清单文件AndroidManifest中配置

// AndroidManifest.xml

<service android:name=".MyIntentService" />

3、调用startService(Intent)启动IntentService

  Intent service = new Intent(this, MyIntentService.class);
  startService(service);

2.2 源码简单分析

1、IntentService是Service的子类,拥有Service的所有生命周期方法,内部还有一个ServiceHandler

// IntentService.java源码

public abstract class IntentService extends Service {
    // ServiceHandler继承Handler,创建时必须传入一个Looper
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }

   protected abstract void onHandleIntent(@Nullable Intent intent);
}

2、onCreate()的源码,创建HandlerThread。

// IntentService.java源码

    @Override
    public void onCreate() {
        super.onCreate();

        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

IntentService服务开启后就会创建Handler线程(HandlerThread),并获取当前线程的Looper对象,然后关联到Handler中。

3、接下来是onStart()源码,调用mServiceHandler

   @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

当你启动IntentService的时候,就会产生一条附带startId和Intent的 Message并发送到MessageQueue中,接下来Looper发现MessageQueue中有Message的时候,就会停止Handler 处理消息。

4、handleMessage处理消息的代码

 public void handleMessage(Message msg) {
      onHandleIntent((Intent)msg.obj);
      stopSelf(msg.arg1);
 }

接着调用 onHandleIntent((Intent)msg.obj),这是一个抽象的方法,其实就是我们要重写实现的方法,我们可以在这个方法里面处理我们的工作.当任务完成时就会调用stopSelf(msg.arg1)这个方法来结束指定的工作。

5、stopSelf(msg.arg1)
回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.如果传入的是-1则直接销毁。

6、onDestroy()

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

服务结束后调用这个方法 mServiceLooper.quit()使looper停下来。

2.3 问题记录

1、在源码handleMessage方法中为什么执行完handleIntent方法会去调用带参数的stopSelf()
因为stopSelf()的执行会立刻将服务停止掉(内部实现调用带参数的stopSelf,传入的值是-1),而带参数的stopSelf(int startId)会在所有任务执行完毕后将服务给停止。通常情况下调用stopSelf(int satrtId)方法不会立刻去执行停止服务的操作,会去判断最近执行任务的getLastStartId是否和startId相等,如果相等就立刻执行停止服务的操作。

3. AsyncTask

为了简化在子线程中访问UI的过程,系统提供了AsyncTask,但不同的API版本AsyncTask具有不同的表现。

AsyncTask是一种轻量级的异步任务类,可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程中更新UI。AsyncTask=Thread+Handler

AsyncTask是一个抽象的泛型类,它提供了Params,Progress,Result这三个泛型参数。

  • Params 参数类型
  • Progress 后台任务的执行进度类型
  • Result 后台任务的返回结果类型
public abstract class AsyncTask<Params, Progress, Result> { }

AsyncTask提供了4个核心方法
1、 onPreExecute() 在主线程中执行,在异步任务执行之前,此方法会被调用,一般用于做一些准备工作

2、doInBackground(Params... params) 在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。此方法需要返回计算结果给onPostExecute方法。

3、onProgressUpdate(Progress... values),在主线程中执行,当后台任务的执行进度发生改变时通过publishProgress方法更新后此方法会被调用。

4、onPostExecute(Result result) 在主线程中执行,在异步任务执行之后,此方法会被调用,其中result参数就是后台任务的返回值,即doInBackground的返回值

除了这个四个方法外,还提供了onCancelled()方法,也是在主线程中执行,当任务被取消时会被调用,但onPostExecute不会被调用。

AsyncTask的源码分析

1、为了分析AsyncTask的工作原理,从execute方法开始分析,execute方法又会调用executeOnExecutor方法

// AsyncTask.java源码
    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return 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.execute(mFuture);

        return this;
    }

sDefaultExecutor是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行。在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先执行,然后线程池开始执行。

2、分析线程池的执行过程

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    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() {
            // 从队列的头部获取一个任务,并赋值给mActive。当队列为空,mActive就为null
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

SerialExecutor的execute的方法把一个任务插入到任务队列mTasks中,如果此时mActive为null,表示没有正在活动的任务,就会调用SerialExecutor的scheduleNext方法来执行下一个任务,当执行完任务后,会从队列中获取下一个任务执行,如果任务队列中没有任务就执行完成。

3、AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),

  • 线程池SerialExecutor用于任务的排队
  • 线程池THREAD_POOL_EXECUTOR用于真正地执行任务
  • InternalHandler用于从线程池切换到主线程执行

在AsyncTask的构造方法中,由于FutureTask的run会调用mWorker的call方法,所以mWorker的call方法最终在线程池中执行。

// AsyncTask的构造方法

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return 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);
                }
            }
        };

在doInBackground执行完后,将返回结果传给postResult方法

    private Result postResult(Result result) {
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

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

        @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:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

Handler收到MESSAGE_POST_RESULT这个消息后会调用AsyncTask的finish方法

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

如果消息被取消了,执行onCancelled方法,否则调用onPostExecute方法。

如果我的文章对您有帮助,不妨点个赞鼓励一下(^_^)


小兵兵同学
56 声望23 粉丝

Android技术分享平台,每个工作日都有优质技术文章分享。从技术角度,分享生活工作的点滴。