Android多线程机制

由于讨论的主要是Android中特有的线程机制和类,因此在此不会再详谈Java中的线程类Thread和Runnable。
Android中可以扮演线程的角色有很多,AsyncTask、IntentService和HandlerThread,AsyncTask的底层实际上就是一个线程池,IntentService的底层实际上就是HandlerThread和Handler,而HandlerThread底层实际上就是Android的消息机制和Thread的组合。

Android中的线程形态

AsyncTask

AsyncTask是一个抽象的泛型类:

public abstract class AsyncTask

AsyncTask的具体使用在这里就不再讨论,我们主要了解其工作原理。

AsyncTask的工作原理

在使用AsyncTask时我们最终都要调用它的execute(Params… params)方法,因此我们从execute方法开始。

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

可以看到execute方法内部调用了executeOnExecutor方法,sDefaultExecutor是一个串行的线程池,一个进程中所有的AsyncTask都在这个线程池中排队执行,这个过程之后再分析,我们先来看看executeOnExecutor方法到底做了些什么事:

public final AsyncTask 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;}

在executeOnExecutor()方法中,首先执行了我们在创建AsyncTask对象时重写的onPreExecute()方法,这个方法大家都很熟悉,就是在执行任务前的准备工作,是一个在主线程中执行的方法。接着将参数构造AsyncTask时传入的参数Params包装成FutureTask对象,在Java中FutureTask就是Runnable的升级版,在这里我们把他当做Runnable就行,最后我们将这个FutureTask交给了线程池去执行。于是我们接着来到这个串行线程池类——SerialExecutor的内部:

private static class SerialExecutor implements Executor {    final ArrayDeque mTasks = new ArrayDeque();    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);        }    }}

在SerialExecutor内部的execute方法中,首先将FutureTask加入到了任务队列mTasks中,如果这时候没有活跃的AsyncTask任务的话,就调用scheduleNext()方法执行下一个AsyncTask任务,并且我们发现execute并不是执行线程任务的方法,真正执行执行任务的方法是scheduleNext(),这个方法将AsyncTask任务又转交给了另一个线程池THREAD_POOL_EXECUTOR去执行,所以AsyncTask底层实际上是利用到了两个线程池:SerialExecutor和THREAD_POOL_EXECUTOR,前者的内部主要是一个任务队列,它取出一个任务就将其交给THREAD_POOL_EXECUTOR去处理。

HandlerThread

HandlerThread是一种使用了Handler消息机制的Thread,它的具体实现非常简单,就是在run方法中通过Looper.prepare()创建了一个消息队列,并通过Looper.loop()开启消息循环,有了Looper的话就可以在实际使用中创建Handler了。

@Overridepublic void run() {    mTid = Process.myTid();    Looper.prepare();    synchronized (this) {        mLooper = Looper.myLooper();        notifyAll();    }    Process.setThreadPriority(mPriority);    onLooperPrepared();    Looper.loop();    mTid = -1;}

由于HandlerThread内部实现实际上是Android消息机制,因此我们要使用HandlerThread时只需要拿到它的Handler并用Handler发送消息即可,我们接着要讲的IntentService内部实现正好就是HandlerThread。

IntentService

IntentService是一种特殊的Service,在IntentService中执行的任务会默认放在子线程中执行,并且由于IntentService继承了Service,是四大组件之一,因此其优先级非常高,比一般的线程更难被系统杀死,因此我们可以将一些非常重要的耗时操作交给IntentService处理。

在启动一个IntentService之前首先会调用onCreate方法:

@Overridepublic void onCreate() {    super.onCreate();    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");    thread.start();    mServiceLooper = thread.getLooper();    mServiceHandler = new ServiceHandler(mServiceLooper);}

可以看到在IntentService的onCreate方法中,首先创建了一个HandlerThread并且让其启动,接着获取到HandlerThread的Looper,并通过Looper获取到了HandlerThread的Handler(这里是特殊的ServiceHandler),有了这个Handler就可以通过消息机制将耗时任务交给HandlerThread处理了。

在每次启动服务的时候系统都会回调onStartCommand()方法:

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

我们发现onStartCommand内部实际上调用的是onStart方法将外部Intent交给了onStart方法处理,于是我们回到onStart():

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

在onStart内部就很简单了,首先得到一个Message,并将intent和id放入Message,通过之前得到的Handler发送将这条消息发送出去就可以了。这里的Intent就是我们外界在startService(intent)时传入的Intent,通过这个Intent就可以解析出外界启动IntentService时传递的参数,通过这些参数就可以区分后台具体要执行什么任务了。

这里我们又会觉得奇怪了,既然我们将消息交给Handler处理了,可是我们之前在学习HandlerThread的时候,发现HandlerThread内部实际上只创建了一个Looper,我们并没有在其中派生Handler的子类并重写handleMessgae()方法,那么到底在哪里处理了消息呢?这里我们需要注意到这里的Handler是ServiceHandler,ServiceHandler是Handler的子类,在ServiceHandler的内部已经帮我们重写了handleMessage()方法:

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

没错,ServiceHandler内部重写的handlerMessage方法帮我们将消息交给了onHandlerIntent来处理,而这个onHandlerIntent方法正是我们在派生IntentService子类的时候要重写的方法!所以最终消息的处理交给了我们自己处理,不得不佩服Android设计人员的聪明才智!

更多相关文章

  1. android EditText控件自动获取焦点弹出键盘解决方法
  2. Unity3d调用android中的方法
  3. Android获取当前已连接的wifi信号强度的方法
  4. 五.在Android中实现线程的方法
  5. Android常见Exception解决方法
  6. android 多线程
  7. 关于Android studio 使用fastjson报错的解决方法
  8. Android消息处理机制

随机推荐

  1. php判断手机浏览还是web浏览,并执行相应的
  2. PHP变量类型+整型类型细节
  3. PHP中的替代语法
  4. 仅在LARAVEL或AJAX中提交表单时,无需用户
  5. JAVA/PHP/C#版RSA验签--转
  6. 十大最流行PHP框架排名
  7. 无法在phpmyadmin中打开一些表
  8. PHP联系表格给用户发送随机确认号码
  9. 谈谈php里的DAO Model AR
  10. PHP:如何通过sprintf()添加前导零/零填充浮