IntentService & HandlerThread源码解析

IntentService

IntentService继承自Service,可以处理异步的请求(通过intent传递参数).客户端通过startService(intent)来发送请求,service开始之后在线程里按顺序处理每一个intent,当它运行完所有任务之后会自动停止。

如何使用:继承IntentService,实现onHandleIntent(Intent)这个方法,intentService会接受intents,启动一个工作线程,在合适的时候停止这个service。

所有的请求都在一个工作线程里边被处理,他们可以长时间运行而且不会阻塞应用的主线程,但是同时只能处理一个请求。

首先来看onCreate方法
onCreate里生成一个HandlerThread,并通过start()启动该线程,然后生成一个ServiceHandler

@Override
public void onCreate() {
    /* TODO:最好在这有一个处理部分wakelock(这个坑先留着)的选项,
    而且应该有一个静态的startService(context,intent)方法启动service同时切换wakelock */
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

这是生成的线程中处理消息的Handler(私有final内部类)

private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        onHandleIntent((Intent)msg.obj);
        /*通过这里可以看到,当声明的线程里边相关联的MessageLooper里边message被处理完毕之后就会停掉整个service*/
        stopSelf(msg.arg1);
    }
}

onHandleIntent是个抽象方法需要被子类实现,来进行那些需要在非UI线程执行的代码

/**
这个方法是在工作线程中被调用,并且传递了相关的请求参数,同一时间只有一个intent被处理,
但是这个过程是在一个单独的工作线程中运行,所以,如果这些代码长时间运行的话,它会阻塞其他发送到这个intentservice中的请求,
当所有请求都被处理之后intentserice会停掉自己,所以不要手动调动stopSelf.
这个方法中的intent参数就是startService(intent)中的参数
*/
protected abstract void onHandleIntent(Intent intent);`

在onStart里边将intent和startId发送到MessageLooper里边处理,也就是在onHandleIntent中处理

@Override
public void onStart(Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}    
/**
不要重写此方法,
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

/**设置为true,onStartCommand()会返回START_REDELIVER_INTENT,
然后如果进程在onHandleIntent()返回之前死掉了,进程会重新启动同时intent会被重新传入,
如果提交了多个intents,只有最近的那个可以保证重新传入
设置为false,onStartCommand()返回START_NOT_STICKY,如果进程死掉,intent也就陪葬了
*/
public void setIntentRedelivery(boolean enabled) {
    mRedelivery = enabled;
}

onStartCommand中返回值含义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
START_STICKY的兼容版本,不保证进程被杀掉之后onStartCommand会被再次调用
*/

public static final int START_STICKY_COMPATIBILITY = 0;

/**
如果服务进程被杀掉,当它启动后(在onStartCommand返回后)会处于started状态而不重新持有传入的intent,
之后系统会尝试重新生成service.因为它处于started状态,它会保证在生成新的service实例之后调用onstartCommand,
如果在此期间没有任何启动命令被传递到,它被调用的时候会被传入一个null的intent,所以得小心。
这种模式对那些任意时候明确开始或停止的有意义,比如执行背景音乐重复的service
*/


public static final int START_STICKY = 1;

/**
如果服务进程被杀掉,当它启动后(在onStartCommand返回后)没有新的start intents传递给它,
然后使service处于非started状态而且不会重启直到startService(intent)明确的被调用,
这个service不会调用参数为null的intent的onStartCommand方法,
因为如果没有pending intent传入的话,它不会重启。

这种模式对要做一些工作来作为开始的结果是有意义的,
但是当内存不足的时候有可能停止并且会在过后明确的开始他们来做更多的工作。
一个从service获取数据例子:可以schedule一个alarm每隔N分钟通过alarm启动它的servide来获取数据,
当它的onStartCommand从alarm调用,它会schedules一个新的N分钟之后响起的alarm,并且产生一个线程来做网络操作。
当检查的时候如果它的进程被杀掉,service不会重启直到alarm响起。
*/


public static final int START_NOT_STICKY = 2;

/**
如果服务进程被杀掉,当它启动后(在onStartCommand返回后)它会被有计划的重启,
而且最后传入的intent会在onStartComman中重新传入。
如果这个service的进程当他开始之后(在onStartCommand返回之后)被杀死,
然后它会scheduled一个重启并且最后传入的Intent会通过onStartCommand被重新传入.
这个Intent会依然保留scheduled重传直到service调用带有由onStartCommand提供的start ID作为参数的stopSelf。
service不会收到一个带有Intent值为null的onStartComman(Intent, int, int)
因为他只会因为它还没有结束处理发给它的所有Intents而重启(而且任何pending events都会在重新开始的时候传入)
*/


public static final int START_REDELIVER_INTENT = 3;

IntentService的onDestroy退出looper

@Override
public void onDestroy() {
    //Looper退出
    mServiceLooper.quit();
}

HandlerThread

在IntentService中的工作线程是通过HandlerThread实现,HanderThread是一个拥有looper的线程,这个looper可以用来创建Handler类,start()方法必须被调用。

public HandlerThread(String name) {
    super(name);
    //赋予默认的线程优先级
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

/**
这个优先级必须是来自Process,不能是Thread
*/
public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {//做了同步处理
        mLooper = Looper.myLooper();
        //这个notifyAll会唤醒等待获取looper的方法(getLooper()中)
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

在run里边将该线程初始化为Looper,设置优先级,然后循环message队列

/**
回调方法:在looper loops之前的一些准备操作可以通过重写这个方法来完成
*/
protected void onLooperPrepared() {    
}

Handler退出Looper

/**
退出handler线程的looper
调用这个方法会中断handler thread的looper,使message queue里边的所有message都不再运行
在looper被停止之后,任何尝试提交给queue的messages都会失败
调用这个方法有时不安全,因为有些message在looper中断之前不会再被传递,
考虑使用quitSafely来代替以确保所有待执行的任务有序的执行
*/
public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}`

/**
安全的退出handler线程的looper
当所有在messagequeue里边的messages都被执行之后handler线程的looper才会中断,
那些延迟执行messages的都不会再执行
*/
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

/**
返回这个线程关联的looper
如果线程没有开始或因为某些原因isAlive()returns false,这个方法会返回null,
如果这个线程已经开始,这个方法会阻塞直到looper被初始化
*/
public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }
    // 如果这个线程已经开始,这个方法会阻塞直到looper被初始化
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
                } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

综上呢,IntentService继承制Service,内部通过HandlerThread来创建线程和在该线程中生成的Looper完成Handler的消息处理,处理完毕所有通过startService中传入的intent之后就会结束自己。可以通过重写IntentService的onStart方法来改变handler处理message的方式,比如延时。