Android中的多线程

Android多线程机制

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

Android中的线程形态

AsyncTask

AsyncTask是一个抽象的泛型类:

public abstract class AsyncTask<Params, Progress, Result>

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

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

在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了。

@Override
public 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方法:

@Override
public 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()方法:

@Override
public 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():

@Override
public 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设计人员的聪明才智!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值