最近工作实在是太忙了。有很久没有更新博客。在我看来,写博客的目的是为了记录自己学习的过程,通过写下来的方式,加深印象。今天为啥要分析Intentservices呢,其实做android开发
以来我都没有使用过Intentservices。但是我在其他的一些开源项目中看到的,刚刚和项目中的使用场景类似,于是就更进一步,分析一下原理。
在分析之前,我们要搞清楚两个问题。
1. services和thread到底是什么关系?我的结论是没有关系。之所以有人认为他们之间有关系,是因为我们经常会说services在后台运行,以为services就能干一些耗时的操作,其实android中的
四大组件都运行于主线程,要处理一些耗时操作,同样需要开启子线程进行处理。那有人就会说,那为啥不直接创建子线程呢。我觉得services作为四大组件之一,非常便于和activity通信,同时生命周期我们也可以控制,之所以说后台,是指services运行时,没有界面。
2. 如果我们有一个大任务需要分解成多个小任务,每个小任务都需要按顺序执行。对于这种需求,我们的常规思路就是创建多个线程,挨个执行。另外一种思路就是在一个线程中,顺序执行任务逻辑代码。
对于以上提出的两个问题。IntentServices可以完美解决我们的需求。IntentServices有哪些优点呢。
1. IntentServices使用方法和普通的services使用方法是一样的。要么通过startService或者bindService。但是startServices启动多次,每次都可以对应一个任务。按照启动的顺序,挨着触发回调方法onHandleIntent(Intent),我们可以通过传递过来的Intent来区分不同任务。这样就可以达到按顺序执行目的了。
2. IntentServices执行完毕以后,能自我销毁。
基本的使用方法太过简单了,只要是做过android开发的,我相信都能明白了。我这里就不再举例了。接下来,重点分析IntentServices原理吧。
我们首先看看onCreate方法吧。
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
首先是创建了HandlerThread的线程对象。这个HandlerThread是个什么鬼呢。这个类的代码不长,我们可以分析一下。原来是Thread的一个子类。对于我们来说,我们重点看两个方法即可。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
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;
}
调用start方法以后就会执行run方法。其中 Looper.prepare();是创建当前线程的looper对象。常规思路就是创建线程的looper对象以后,就是调用 Looper.loop();进行消息循环。可是为啥还有同步代码块呢。主要原因是在IntentService的onCreate方法中,thread.start()以后,直接调用thread.getLooper()这个时候,HandlerThread的线程run方法可能还没有执行到 Looper.prepare(),或者是说没有执行完。这个时候getLooper肯定是返回null了。为了解决这种时间差的问题,就添加了同步代码块的处理了。说白了HandlerThread就是一个线程而已。(这一块的理解,可能需要读者对Handler、MessageQueue、Looper有一定的理解)。
那我们回去继续看onCreate方法。在第9行获取到在HandlerThread线程对应的Looper对象。用这个Looper对象创建Handler对象,并且重写handleMessage方法。我们看看onstart方法。这个方法的实现代码,我们太熟悉了。就是通过handler发送message。由于在HandlerThread的run方法中已经进入消息循环。这时,我们不妨看看Looper中looper方法吧。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
重点看第27行代码。由于当前的loop方法是在HandlerThread线程中调用的,那么msg.target.dispatchMessage(msg)这一句肯定也是在HandlerThread线程中的。具体dispatchMessage方法中message是如何分发,今天先不讲,但最终会调用重写的handleMessage方法。在这个方法中看到了我们前面提到的使用IntentServices优点,在这里得到了体现。
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);
}
}
如果我们要处理一下耗时操作,我们就可以重写onHandleIntent方法,其实intent参数就是我们startservices的intent。这样就达到顺序执行多个任务。并且通过stopSelf结束自己。
总结:经过IntentServices源码简单,但是通过阅读代码,还是有收获的,而且加深了对IntentServices的理解。随着android开发经验的积累,自己也看过不少的源码了。以后会逐渐分享出来。
还是那句话,代码是最好的学习方式。