1. 定义
IntentService是Android里面的一个封装类,继承自四大组件之一的Service。IntentService,可以看做是Service和HandlerThread的结合体,在完成了使命之后会自动停止,适合需要在工作线程处理UI无关任务的场景。
2. 实例
实例模型:在页面按后退键退出的时候,退出当前页面的同时,开启 IntentService。直接看以下代码:
创建IntentService类:
package cn.zzw.messenger.intentservicedemo;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
public void onCreate() {
super.onCreate();
Log.e("zzw", "MyIntentService: onCreate()");
}
@Override
protected void onHandleIntent(Intent intent) {
//在此方法中执行的是异步操作,耗时操作就在此方法中执行。
Log.e("zzw", "MyIntentService: onHandleIntent()");
for (int i = 0; i <5 ; i++) {
try {
Thread.sleep(1000);
Log.e("zzw", "MyIntentService: onHandleIntent() i="+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("zzw", "MyIntentService: onDestroy()");
}
}
在AndroidManifest中注册 IntentService:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.zzw.messenger.intentservicedemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyIntentService">
<intent-filter>
<action android:name="cn.zzw.intentservice"></action>
</intent-filter>
</service>
</application>
</manifest>
页面对应的Activity:
package cn.zzw.messenger.intentservicedemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onBackPressed() {
super.onBackPressed();
Log.e("zzw", "onBackPressed()");
Intent intent = new Intent();
intent.setAction("cn.zzw.intentservice");
intent.setPackage("cn.zzw.messenger.intentservicedemo");
startService(intent);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("zzw", "MainActivity: onDestroy()");
}
}
结果对应的log:
2019-08-03 21:41:16.795 3852-3852/cn.zzw.messenger.intentservicedemo E/zzw: onBackPressed()
2019-08-03 21:41:16.848 3852-3852/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onCreate()
2019-08-03 21:41:16.849 3852-3951/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onHandleIntent()
2019-08-03 21:41:17.753 3852-3872/cn.zzw.messenger.intentservicedemo D/EGL_emulation: eglMakeCurrent: 0xe4105300: ver 2 0 (tinfo 0xe41036c0)
2019-08-03 21:41:17.801 3852-3852/cn.zzw.messenger.intentservicedemo E/zzw: MainActivity: onDestroy()
2019-08-03 21:41:17.851 3852-3951/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onHandleIntent() i=0
2019-08-03 21:41:18.893 3852-3951/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onHandleIntent() i=1
2019-08-03 21:41:19.908 3852-3951/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onHandleIntent() i=2
2019-08-03 21:41:20.945 3852-3951/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onHandleIntent() i=3
2019-08-03 21:41:21.961 3852-3951/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onHandleIntent() i=4
2019-08-03 21:41:21.964 3852-3852/cn.zzw.messenger.intentservicedemo E/zzw: MyIntentService: onDestroy()
从以上的Log可以看出,当页面按了后退键的时候,IntentService 被开启,并调用了 onCreate() 方法,以及 onHandleIntent() 方法。虽然页面对应的Activity已经调用了 Finish() 方法,并且 Activity也已经调用了 onDestroy() 方法。但是可以看出 IntentService 依然还在执行,直到 onHandleIntent() 方法中的耗时操作执行完毕后,IntentService 才会执行 onDestroy() 方法。
3. 实现步骤
通过以上的实例,可以概括出实现IntentService的步骤如下:
a. 定义IntentService的子类:传入线程名称、复写onHandleIntent()方法
b.在Manifest.xml中注册服务
c. 在Activity中开启Service服务
4. 源码分析
从下面代码可以看出:IntentService 是一个抽象类并且继承自Service。
public abstract class IntentService extends Service
{
...
}
接下来看构造方法:
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
在构造方法中,必须传入一个String类型的名字,当做当前工作线程的名字。
由于 IntentService 继承自Service,所有它有Service对应的生命周期。在 IntentService 的源码中,重写了 Service 的 onCreate() 、onStart()、onStartCommand()、onBind()、onDestroy()。
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 + "]");//1
thread.start();
mServiceLooper = thread.getLooper();//2
mServiceHandler = new ServiceHandler(mServiceLooper);//3
}
在注释1:创建了 HandlerThread ,HandlerThread继承自Thread,内部封装了 Looper,通过实例化HandlerThread新建线程并启动,所以使用IntentService时不需要额外新建线程。而对于 HandlerThread 的介绍,看此篇文章:HandlerThread 的使用及源码解析。
注释2:获得工作线程(HandlerThread)的 Looper。
注释3:创建 Handler(ServiceHandler) ,并将注释2中的 Looper 对象传入 Handler。内部Handler与HandlerThread所对应的子线程进行绑定。ServiceHandler内部就持有异步线程的Looper,自然就可以执行异步任务了。
ServiceHandler代码如下:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);//4
stopSelf(msg.arg1);//5
}
}
ServiceHandler的分析稍后再来。
当我们调用startService的启动Service,会调用到 onStartCommand() 方法:
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId); //6
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
在这个方法中,只调用到方法: onStart(intent, startId) 方法(注释6)。
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
在这个方法中,将接收到的Intent传递到 Handler 中。这时候再回头看 ServiceHandler的代码:
注释4中:执行了方法 onHandleIntent()。这个方法就是我们执行耗时等异步操作的方法。
注释5中:调用了方法 stopSelf(msg.arg1)。
stopSelf() 是父类 Service 中的方法,在此方法中,会将当前Service关闭。这也就是为什么IntentService 执行完毕后会关闭Service的原因。
/**
* Old version of {@link #stopSelfResult} that doesn't return a result.
*
* @see #stopSelfResult
*/
public final void stopSelf(int startId) {
if (mActivityManager == null) {
return;
}
try {
mActivityManager.stopServiceToken(
new ComponentName(this, mClassName), mToken, startId);
} catch (RemoteException ex) {
}
}
从上面源码可以看出,IntentService本质是采用Handler & HandlerThread方式:
a. 在onCreate()方法中通过HandlerThread单独开启一个名为IntentService的线程;
b. 创建一个名叫ServiceHandler的内部Handler,并把内部Handler与HandlerThread所对应的子线程进行绑定;
c. 通过onStartCommand()传递给服务intent,依次插入到工作队列中,并逐个发送给onHandleIntent();
d. 通过onHandleIntent()来依次处理所有Intent请求对象所对应的任务。
e. 执行完消息后,调用Service中的方法 stopSelf() 来关闭IntentService。
5. 注意事项
5.1 不建议通过 bindService() 启动 IntentService
上面的实例中,我们是通过 StartService() 方法来启动 IntentService ,既然它是一个 Service,那是不是也能用 bindService来启动Service呢?
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
从上面的源码可以看出,onBind() 方法返回的是null,而采用bindService() 启动 IntentService的生命周期是:onCreate() —>onBind()—>onunbind()—>onDestory() 并不会调用 onstartcommand() 方法以及 onstart() 方法,所以不会将消息发送到消息队列,那么onHandleIntent()将不会回调,即无法实现多线程的操作。
5.2 工作任务队列是顺序执行的
如果一个任务正在IntentService中执行,此时再发送一个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕才开始执行。由于onCreate() 方法只会调用一次,所以只会创建一个工作线程;当多次调用 startService(Intent) 时(onStartCommand也会调用多次)其实并不会创建新的工作线程,只是把消息加入消息队列中等待执行,所以,多次启动 IntentService 会按顺序执行事件。如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。