概述
Service
作为Android开发常用的组件之一,在上一篇学习笔记中,对Service
做了一个简单的学习。明白了Service
分为后台服务,前台服务,绑定服务。不管是哪种服务,都是通过继承Service
实现的,只是启动方式不一样:后台服务通过startService
启动,前台服务通过startForegroundService
启动,同时需要指定一个通知和当前的服务进行绑定,绑定服务则通过bindService
进行绑定启动。
通常我们使用Service
的时候,由于Service
也是运行在主线程,所以对于一些耗时操作,我们还是会开启一个或多个工作线程去执行任务,在这种情况下我们就需要自己去管理和维护这些线程,这可能会造成一些危险的操作。而如果我们并不需要同时处理多个任务,Android推荐我们使用IntentService
。
IntentService
是Service
的子类,它使用工作线程逐一处理启动请求,在不要求同时处理多个任务的情况下,这是最佳的选择。我们通过继承IntentService
类,然后实现其中的onHandleIntent()
方法来执行我们需要的操作,这个方法接收每个启动请求的Intent
,以便我们传递需要处理的数据。
源码预览
通过上面的介绍,我们已经对IntentService
有了一个大概的了解:
Service
的子类,那么生命周期应该和Service
是一致的,应该也支持startService
和bindService
两种方式启动- 使用工作线程说明
IntentService
已经帮我们实现了在工作线程处理任务 - 逐一处理启动请求说明每次只能处理一次启动请求,如果存在多个请求,那么首先进来的请求首先会被处理
通过阅读IntentService
的源码,我们可以查看是否能够对应上面三点的内容:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
@UnsupportedAppUsage
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
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;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@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;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
可以看到,IntentService
的源码非常少,我们按照Service
的生命周期函数去查看其中的代码。
onCreate()
-
onCreate()
不管通过那种方式启动
Service
,首先都会执行onCreate()
方法,并且这个方法只能被执行一次,我们通常会在这个方法中执行一些初始化的操作,这个方法中现在执行了如下操作:@Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }
首先创建了
HandlerThread
对象,下面是HandlerThread
的源码:public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; private @Nullable Handler mHandler; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } public HandlerThread(String name, int priority) { super(name); mPriority = priority; } protected void onLooperPrepared() { } public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } 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; } @NonNull public Handler getThreadHandler() { if (mHandler == null) { mHandler = new Handler(getLooper()); } return mHandler; } public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } public int getThreadId() { return mTid; } }
可以看到,
HandlerThread
类是继承自Thread
类,那么此处创建这个HandlerThread
类的对象也就相当于创建了一个线程对象,接下来调用thread.start()
方法也就相当于开启了这个线程。我们知道,调用start()
方法的时候会开启一个新的线程去执行run()
,下面是run()
方法的源码:public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
在新的线程中,首先调用了
Looper.prepare()
方法,如下是这个方法的源码:public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
这里是直接调用了
prepare(true)
这个重载函数,在这里从ThreadLocal
中获取Looper
对象,如果Looper
已经存在了则会抛出异常,否则就创建一个Looper
对象,然后保存在ThreadLocal
中,ThreadLocal
中保存的对象是和当前线程绑定的,在其他线程中无法对这个对象做任何操作。下面进入到创建Looper(true)
对象的代码中:private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
在这里又创建了
MessageQueue(true)
对象,并在Looper
中保存了当前线程的对象,下面是创建MessageQueue
对象的方法:MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
通过上面的一系列代码,其实我们已经可以了解到,这就是创建了一个消息循环机制,和我们之前使用的
Handler
是一样的,只不过之前我们一直在UI线程中使用,并没有关心UI线程的消息循环机制是如何创建的。至此,消息循环机制中的Looper
和MessageQueue
都被创建好了。和UI线程中的消息循环机制不同的地方在于,UI线程中的消息循环机制是不能退出的,而这里的消息循环机制是允许退出的。 -
继续回到
HandlerThread.run()
方法中,上面创建好了Looper
和MessageQueue
,接下来的代码如下:@Override public void run() { mTid = Process.myTid(); //这一步创建好了Looper和MessageQueue Looper.prepare(); synchronized (this) { //将当前Looper保存下来并唤醒线程 mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); //这是一个空实现的方法,子类可以实现此方法做一些操作 onLooperPrepared(); //调用loop()方法 Looper.loop(); mTid = -1; }
上面的注释中已经对执行流程写的比较清除了,比较重要的就是
notifyAll()
和Looper.loop()
方法,为什么要唤醒线程下一步介绍,而对于Looper.loop()
方法,其内部通过一个for
循环不断获取MessageQueue
中的下一条Message
,这是一个死循环,当获取不到Message
的时候会退出。 -
在上一步中我们已经创建好了消息循环机制,继续看
onCreate()
中的代码:mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper);
在这里,首先会获取上一步创建好的
Looper
,然后创建ServiceHandler(mServiceLooper)
将之前创建好的Looper
传递进去,下面是HandlerThread.getLooper()
方法的源码: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; }
上面的代码中可以看到,如果当前的
Looper
是空的,那么就会让线程等待,因为我们上面已经提到过了,在执行run()
方法时就会创建Looper
,配合这里,我们就明白了,如果Looper
没有创建好就获取则会出问题,所以这里是一个死循环,如果Looper
为空就一直等着,等到Looper
创建完成后会调用notify()
唤醒线程,此时就能正常获取到Looper
了。而
ServiceHandler
是继承自Handler
,我们需要在创建ServiceHandler
的时候传递Looper
进去,这样,这个ServiceHandler
就知道应该把消息添加到哪个线程的队列当中去了,这一点从Handler
的构造函数中可以看出,如下所示:public Handler(@Nullable Callback callback, boolean async) { ...无关代码... mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
从上面的代码可以看出,如果我们不指定
Looper
,那么这里会直接使用Looper.myLooper()
获取当前线程的Looper
,而由于我们的Handler
是在主线程中创建的,所以此时如果不传Looper
,这里直接就是主线程的Looper
,而我们本来希望的是在工作线程处理数据,如果不传这个Looper
,很可能出现ANR
。至此,我们就了解了在
IntentService
的onCreate()
方法中执行了哪些操作,主要就是创建了HandlerThread
,也就是创建了一个工作线程,同时为这个线程绑定了事件处理机制。然后创建了一个ServiceHandler
,这就是一个Handler
,用于提交和处理数据。
onStartCommand()
当我们通过startService()
方法启动IntentService
后,在执行完onCreate()
方法后,接下来就会执行onStartCommand()
方法,下面是这个方法的源码:
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
可以看到,在这里是直接调用了onStart()
方法,然后根据mRedelivery
参数的值返回一个常量。如果mRedelivery
为true
,则返回START_REDELIVER_INTENT
,这个常量的大概意思是如果Service
被意外中止,那么在重新启动这个Service
的时候,会将最后一次提交的Intent重新交给这个Service
。如果mRedelivery
为false
,则返回START_NOT_STICKY
,这个常量的意思是如果service
被意外终止,直到重新调用context.startService()
方法,才会重新启动这个Service
,并且不会提交最后一次的Intent
数据。
我们可以在子类中通过调用setIntentRedelivery()
方法设置这个值的参数。
onStart()
上面已经了解到,在onStartCommand()
方法中其实是调用了onStart()
方法,这个方法的源码如下:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看到,在这里就是创建了一个Message
,然后将我们传递的Intent
作为参数设置给Message
,然后将这个Message
发送出去,这里是通过Handler
发送出去的,所以直接在Handler
中查找处理数据的方法:
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);
}
}
我们直到,Handler
中处理数据的方法是handleMessage
,在上面的方法中,直接调用了onHandleIntent()
方法,这是需要子类去实现的方法,然后调用了stopSelf()
关闭当前的服务。
至此,我们就了解了IntentService
全部的工作机制,总的来说就是如下过程:
- 首先创建一个线程,并为这个线程创建一个
Looper
,这样,这个线程就具有了事件传递的能力。 - 创建一个
Handler
,并将上一步线程的Looper
传递给这个Handler
,这样,通过Handler
处理的事件就会在上面创建的工作线程中执行 - 通过
startService(Intent)
启动当前服务,将我们需要处理的数据设置到Intent
中,如果是第一次启动服务,此时会先执行onCreate()
,接着执行onStartCommand(Intent)
,否则直接执行onStartCommand(Intent)
- 在
IntentService
的onStartCommand(Intent)
中会调用onStart(Intent,id)
方法,在这个方法里面,会创建一个Message
,将包含我们数据的Intent
和标志服务的id
设置到这个Message
中,分别作为Message
的obj
和arg1
的参数的值 - 通过上面创建的
Handler
发送第4步创建的Message
进入到事件序列中 Handler
中获取到需要处理的事件Message
会调用onHandleIntent()
方法,我们需要实现这个方法书写自己的逻辑- 当服务中的所有事件都被执行完成以后会调用
stopSelf()
自动关闭服务
至此,整个执行流程就结束了。
通过onBind()启动服务
其实对于通过onBind()
方式启动IntentService
我个人认为这是不太适合的,因为onBind()
方法在启动服务的时候只会调用一次,所以只能在绑定成功后去执行任务,而且由于我们在页面关闭的时候一般会关闭连接,所以就导致任务可能执行不完就被结束了,不过如果我们确实需要这样的效果,也是可以做到的,下面的步骤演示了如何通过onBind()
方式绑定一个服务。
-
继承
IntentService
实现自己的Service
:class MyIntentService : IntentService("MyIntentService") { private val mBinder by lazy { MyIntentServiceBinder() } var mValueListener: IntentServiceStudyActivity.IntentServiceValueListener? = null override fun onHandleIntent(intent: Intent?) { //线程休眠 Thread.sleep(1 * 1000) intent?.let { val value = it.getStringExtra("key") Logs.e("value is $value") } } override fun onCreate() { Logs.e("onCreate...") super.onCreate() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Logs.e("onStartCommand...") return super.onStartCommand(intent, flags, startId) } override fun onDestroy() { Logs.e("onDestroy...") super.onDestroy() } override fun onBind(intent: Intent?): IBinder { super.onStart(intent, 0) return mBinder } inner class MyIntentServiceBinder : Binder() { fun getService(): MyIntentService = this@MyIntentService } }
-
在
Activity
中创建连接:private val mServiceConnection by lazy { object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { mBindIntentServiceSuccess = true service?.let { for (i in 1 until 10) { val intent = Intent() intent.putExtra("key", "value$i") binder.getService().onBind(intent) } } } override fun onServiceDisconnected(name: ComponentName?) { Logs.e("服务连接断开") mBindIntentServiceSuccess = false } } }
可以看到,这里连接到服务之后创建了
Intent
,然后将我们需要的数据设置进去,在这里是直接调用了Service.onBind()
方法,其实只要是Service
中公开的方法都可以。通过上面两步就绑定了服务,也可以正常处理数据,但是
onBind()
方法不知道能否这样直接调用,暂时没发现什么问题,可以在Service
中定义其它的公开的方法去调用。