此篇对IntentService进行详细的讲解
一.简介
英文解释
IntentService is a base class forServices that handle asynchronous requests (expressed asIntents) on demand. Clients send requests throughstartService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work。
翻译
IntentService是按需处理异步请求(表示的意图)的服务的基类。客户端通过startservice (Intent)调用发送请求;该服务根据需要启动,使用工作线程依次处理每个意图,并在耗尽工作时停止自身。
理解
简单说,IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。
其实IntentService是专门解决Service中不能进行耗时操作的。
二.Demo
启动式服务
<1> 服务
package com.example.test.component;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
public void onCreate() {
super.onCreate();
Log.i("MyIntentService","onCreate方法执行Thread----:"+Thread.currentThread().getName());
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
if(intent!=null){
String name=intent.getStringExtra("name");
String age=intent.getStringExtra("age");
Log.i("MyIntentService", "onStartCommand方法中name----:"+name);
Log.i("MyIntentService", "onStartCommand方法中age----:"+age);
}
Log.i("MyIntentService","onStartCommand方法执行Thread----:"+Thread.currentThread().getName());
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
String name=intent.getStringExtra("name");
String age=intent.getStringExtra("age");
Log.i("MyIntentService", "onHandleIntent方法中name----:"+name);
Log.i("MyIntentService", "onHandleIntent方法中age----:"+age);
//直接进行耗时操作 比如 下载文件 链接网络 下载图片...
for(int i=0;i<10;i++){
Log.i("MyIntentService", "onHandleIntent方法中模拟耗时操作i----:"+i);
}
Log.i("MyIntentService", "onHandleIntent方法执行Thread----:"+Thread.currentThread().getName());
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("MyIntentService", "onDestroy方法执行Thread----:"+Thread.currentThread().getName());
}
}
注意
(1) 关于构造方法
IntentService的构造方法
public MyIntentService(String name) {
super(name);
}
报错:
java.lang.RuntimeException: Unable to instantiate service com.finddreams.runningman.MyIntentService: java.lang.InstantiationException: can't instantiate class com.finddreams.runningman.MyIntentService; no empty constructor
IntentService的构造方法
public MyIntentService() {
super("MyIntentService");
}
正确
(2) 系统创建IntentService,默认只创建构造方法和onHandleIntent方法。其他方法均未重写,切手动重写时均显示已过期的标识。
<2> 注册
<service
android:name=".component.MyIntentService"
android:exported="false">
</service>
<3> 启动
Intent intent=new Intent(IntentServiceActivity.this,MyIntentService.class);
intent.putExtra("name", "张三");
intent.putExtra("age", "18");
startService(intent);
<4> 结果
点击一次开启
I/MyIntentService: onCreate方法执行Thread----:main
I/MyIntentService: onStartCommand方法中name----:张三
I/MyIntentService: onStartCommand方法中age----:18
I/MyIntentService: onStartCommand方法执行Thread----:main
I/MyIntentService: onHandleIntent方法中name----:张三
I/MyIntentService: onHandleIntent方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9
I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]
I/MyIntentService: onDestroy方法执行Thread----:main
点击两次开启
I/MyIntentService: onCreate方法执行Thread----:main
I/MyIntentService: onStartCommand方法中name----:张三
I/MyIntentService: onStartCommand方法中age----:18
I/MyIntentService: onStartCommand方法执行Thread----:main
I/MyIntentService: onHandleIntent方法中name----:张三
I/MyIntentService: onHandleIntent方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9
I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]
I/MyIntentService: onDestroy方法执行Thread----:main
I/MyIntentService: onCreate方法执行Thread----:main
I/MyIntentService: onStartCommand方法中name----:张三
I/MyIntentService: onStartCommand方法中age----:18
I/MyIntentService: onStartCommand方法执行Thread----:main
I/MyIntentService: onHandleIntent方法中name----:张三
I/MyIntentService: onHandleIntent方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9
I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]
I/MyIntentService: onDestroy方法执行Thread----:main
<5> 说明
(1) 通过以上的输出结果我们可以发现,MyIntentService的onCreate、onStartCommand、onDestroy等回调方法都是运行在主线程中的,而onHandleIntent是运行在工作线程IntentService[MyIntentService]中的,这验证了我们上面所说的IntentService的第一个和第二个特点。即只有onHandleIntent方法运行在子线程中,其他生命周期方法和构造方法运行在UI线程。
(2)如果我们连续调用了多次startService(intent)之后,onStartCommand依次被调用了多次,然后依次执行了onHandleIntent多次,这样就依次完成了job,当最后一个job完成,也就是在最后一次onHandleIntent调用完成之后,整个IntentService的工作都完成,执行onDestroy回调方法,IntentService销毁。
绑定式服务
<1> 服务
package com.example.test.component;
import android.app.IntentService;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
public void onCreate() {
super.onCreate();
Log.i("MyIntentService","onCreate方法执行Thread----:"+Thread.currentThread().getName());
}
@Override
public IBinder onBind(Intent intent) {
if(intent!=null){
String name=intent.getStringExtra("name");
String age=intent.getStringExtra("age");
Log.i("MyIntentService", "onBind方法中name----:"+name);
Log.i("MyIntentService", "onBind方法中age----:"+age);
}
Log.i("MyIntentService","onBind方法执行Thread----:"+Thread.currentThread().getName());
return new MyBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("MyIntentService","onUnbind方法执行Thread----:"+Thread.currentThread().getName());
return super.onUnbind(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
String name=intent.getStringExtra("name");
String age=intent.getStringExtra("age");
Log.i("MyIntentService", "onHandleIntent方法中name----:"+name);
Log.i("MyIntentService", "onHandleIntent方法中age----:"+age);
//直接进行耗时操作 比如 下载文件 链接网络 下载图片...
for(int i=0;i<10;i++){
Log.i("MyIntentService", "onHandleIntent方法中模拟耗时操作i----:"+i);
}
Log.i("MyIntentService", "onHandleIntent方法执行Thread----:"+Thread.currentThread().getName());
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("MyIntentService", "onDestroy方法执行Thread----:"+Thread.currentThread().getName());
}
/**
* 代理类
*/
class MyBinder extends Binder {
public String testMethod1() {
return "绑定的服务返回给调用者的回调";
}
public int testMethod2() {
return 20;
}
public void testMethod3() {
Log.d("MyIntentService", "绑定者调用了服务的testMethod3()方法");
}
}
}
<2> 绑定
package com.example.test.component;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.test.R;
public class IntentServiceActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intentservice);
TextView textView=findViewById(R.id.activity_intentservice_textview);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent bindIntent=new Intent(IntentServiceActivity.this, MyIntentService.class);
bindIntent.putExtra("name", "张三");
bindIntent.putExtra("age", "18");
startService(bindIntent);
bindService(bindIntent, MyServiceConnection, BIND_AUTO_CREATE);
}
});
}
/**
* ServiceConnection 接口实现类
*/
ServiceConnection MyServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取绑定式服务的代理类
MyIntentService.MyBinder binder = (MyIntentService.MyBinder) service;
//调用绑定式服务的各种方法
String s = binder.testMethod1();
int n = binder.testMethod2();
binder.testMethod3();
Log.i("MyIntentService", "onServiceConnected方法name----:" + name);
Log.i("MyIntentService", "绑定者获取服务的s----:" + s);
Log.i("MyIntentService", "绑定者获取服务的n----:" + n);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("MyIntentService", "onServiceDisconnected方法name----:" + name);
}
};
}
<3> 结果
绑定一次
I/MyIntentService: onCreate方法执行Thread----:main
I/MyIntentService: onHandleIntent方法中name----:张三
I/MyIntentService: onHandleIntent方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1
I/MyIntentService: onBind方法中name----:张三
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2
I/MyIntentService: onBind方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4
I/MyIntentService: onBind方法执行Thread----:main
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9
I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]
I/MyIntentService: onServiceConnected方法name----:ComponentInfo{com.example.test/com.example.test.component.MyIntentService}
I/MyIntentService: 绑定者获取服务的s----:绑定的服务返回给调用者的回调
I/MyIntentService: 绑定者获取服务的n----:20
绑定两次
I/MyIntentService: onCreate方法执行Thread----:main
I/MyIntentService: onHandleIntent方法中name----:张三
I/MyIntentService: onHandleIntent方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4
I/MyIntentService: onBind方法中name----:张三
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6
I/MyIntentService: onBind方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8
I/MyIntentService: onBind方法执行Thread----:main
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9
I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]
I/MyIntentService: onServiceConnected方法name----:ComponentInfo{com.example.test/com.example.test.component.MyIntentService}
I/MyIntentService: 绑定者获取服务的s----:绑定的服务返回给调用者的回调
I/MyIntentService: 绑定者获取服务的n----:20
I/MyIntentService: onHandleIntent方法中name----:张三
I/MyIntentService: onHandleIntent方法中age----:18
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8
I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9
I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]
退出APP
I/MyIntentService: onUnbind方法执行Thread----:main
I/MyIntentService: onDestroy方法执行Thread----:main
<4> 说明
绑定式服务onHandleIntent方法执行完成后,没有自动释放,退出页面或者APP时才调用。
三.源码
在上面我们已经介绍了IntentService的特点以及如何使用,那么你可能会疑问Android是如何将调度这些intent将其传入onHandleIntent完成工作的呢。
其实IntentService的工作原理很简单,将intent转换为Message并放到消息队列中,然后让Handler依次从中取出Message对其进行处理。
IntentService的源码
package android.app;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
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,确保onHandleIntent不会阻塞主线程
onHandleIntent((Intent)msg.obj);
//在执行完了onHandleIntent之后,我们需要调用stopSelf(startId)声明某个job完成了
//当所有job完成的时候,Android就会回调onDestroy方法,销毁IntentService
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
//此处的name将用作线程名称
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
//创建HandlerThread,利用mName作为线程名称,HandlerThread是IntentService的工作线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
//将创建的HandlerThread所绑定的looper对象传递给ServiceHandler,
//这样我们创建的Handler就和HandlerThread通过消息队列绑定在了一起
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
//在此方法中创建Message对象,并将intent作为Message的obj参数,
//这样Message与Intent就关联起来了
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
//将关联了Intent信息的Message发送给Handler
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//IntentService重写了onStartCommand回调方法:在内部调用onStart回调方法
//所以我们在继承IntentService时,不应该再覆写该方法,即便覆盖该方法,我们也应该调用super.onStartCommand()
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
//在onDestroy方法中调用了Handler的quit方法,该方法会终止消息循环
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
protected abstract void onHandleIntent(Intent intent);
}
IntentService继承自Service类,并且IntentService重写了onCreate、onStartCommand、onStart、onDestroy回调方法,并且IntentService还添加了一个onHandleIntent回调方法。
<1> onCreate方法
在onCreate回调方法中,利用mName作为线程名称,创建HandlerThread,HandlerThread是IntentService的工作线程。HandlerThread在执行了start方法之后,其本身就关联了消息队列和Looper,并且消息队列开始循环起来。
<2> onStartCommand方法
IntentService重写了onStartCommand回调方法,在内部调用onStart回调方法。
<3> onStart方法
在onStart方法中创建Message对象,并将intent作为Message的obj参数,这样Message与Intent就关联起来了。然后通过Handler的sendMessage方法将关联了Intent信息的Message发送给Handler。
<4> onHandleIntent方法
当在onStart方法中,通过sendMessage方法将Message放入到Handler所关联的消息队列中后,Handler所关联的Looper对象会从消息队列中取出一个Message,然后将其传入Handler的handleMessage方法中。
在handleMessage方法中首先通过Message的obj获取到了原始的Intent对象,然后将其作为参数传给了onHandleIntent方法让其执行。
handleMessage方法是运行在HandlerThread的,所以onHandleIntent也是运行在工作线程中的。在执行完了onHandleIntent之后,我们需要调用stopSelf(startId)声明某个job完成了。当所有job完成的时候,Android就会回调onDestroy方法,销毁IntentService。
<5> onDestroy方法
当所有job完成的时候,Service会销毁并执行其onDestroy回调方法。在该方法中,调用了Handler的quit方法,该方法会终止消息循环。
<6> 总结
IntentService可以在工作线程中完成工作而不阻塞主线程,但是IntentService不能并行处理多个job,只能依次处理,一个接一个,当所有的job完成后,会自动执行onDestroy方法而无需我们自己调用stopSelf()或stopSelf(startId)方法。IntentService和Service去了这样的差别之外,就没有什么区别了,比如注册一样,启动方式一样(启动式 绑定式)等等。
当我们通过startService多次启动了IntentService,这会产生多个job,由于IntentService只持有一个工作线程,所以每次onHandleIntent只能处理一个job。面对多个job,IntentService会如何处理?处理方式是one-by-one,也就是一个一个按照先后顺序处理,先将intent1传入onHandleIntent,让其完成job1,然后将intent2传入onHandleIntent,让其完成job2…这样直至所有job完成,所以我们IntentService不能并行的执行多个job,只能一个一个的按照先后顺序完成,当所有job完成的时候IntentService就销毁了,会执行onDestroy回调方法。