简介
IntentService
是一个继承自Service的抽象类,本质上还是一个Service,我们需要创建它的子类去使用。
IntentService
同时实现了
HandlerThread
,在内部维护了一个
WorkerThread
线程,专门用来处理耗时操作。实际上
IntentService
中所有的操作都是在这个
WorkerThread
中执行的。
多次启动同一个IntentService,则每一次启动的耗时任务,都会以消息队列的形式在WorkerThread中被依次执行,任务的执行是在onHandleIntent()方法中完成的。都执行完成后,就会调用 stopSelf() 自动结束,不需要我们去手动结束
。
优点
1. 优先级比较高,被杀死的几率低:
本质上
IntentService
也是开启了一个子线程,但是
IntentService
是继承自
Service
的,所以根据 Android系统Kill App的机制,使用
IntentService
的应用优先级更高一些。通俗点说,如果使用 IntentService 做为后台任务,当程序退到后台时,被杀死的几率会更低。
2.自动调用stopSelf()方法结束:
IntentService 会在任务执行完成后,自行结束,不需要外部调用 stopService();
缺点
由于 IntentService 里面维护的是一个 HandlerThread,里面的异步任务都是保存在队列里面的,因此
只能实现 单线程-多任务-同步执行
,对于想要实现多线程并发的业务需求,这个不适合。
特点
1.内部创建独立线程 WorkerThread ,来处理所有的 Intent 请求。
2.内部创建独立线程 WorkerThread ,来处理 onHandleIntent() 里面的耗时逻辑,无需担心多线程的问题。
3.所有的耗时任务完成之后,IntentService 调用 stopSelf() 自动停止。
4.
不能使用 bindService() 来绑定一个 IntentService
。
5.onBInd()方法返回null,也无需关心。
6.
onStartCommand() 提供了默认的实现,会将请求的Intent任务添加到队列中
。
如何使用
IntentService 类似于一个单例,多次启动同一个IntentService类,onCreate() 只执行一次,
onStart / onStartCommand 的执行次数 = 启动次数,onHandleIntent() 方法会依次执行队列中的intent 任务。
public class MyService extends IntentService {
//这里必须有一个空参数的构造实现父类的构造,否则会报异常
//java.lang.InstantiationException:
//java.lang.Class<***.MyService> has no zero argument constructor
public MyService() {
super("");
}
@Override
public void onCreate() {
System.out.println("onCreate");
super.onCreate();
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
System.out.println("onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
System.out.println("onStart");
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
System.out.println("onDestroy");
super.onDestroy();
}
//这个是IntentService的核心方法,它是通过串行来处理任务的,也就是同步处理
@Override
protected void onHandleIntent(@Nullable Intent intent) {
System.out.println("工作线程是: "+Thread.currentThread().getName());
String task = intent.getStringExtra("task");
System.out.println("任务是 :"+task);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,MyService.class);
intent.putExtra("task","播放音乐");
startService(intent);
intent.putExtra("task","播放视频");
startService(intent);
intent.putExtra("task","播放图片");
startService(intent);
}
}
源码分析
// IntentService 的 onCreate() 方法,内部启动了一个 HandlerThread 线程。
@Override
public void onCreate() {
super.onCreate();
//HandlerThread 就是一个带有 handler 的 thread ,这里就是创建了一个线程,
//注意这个线程的名字上面的日志打印中"工作线程是: IntentService[]"
//因为我们在自定义的MyService里面,构造方法写的是super(""),如果写的不是空串,
//上面的日志打印就应该是"工作线程是: IntentService[我们定义的名称]"
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//获取这个线程的looper
mServiceLooper = thread.getLooper();
//创建了一个handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
//我们来看一下 ServiceHandler 对消息的处理
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//处理逻辑是我们在MyService里面重写的这个方法
onHandleIntent((Intent)msg.obj);
//从这里可以看出,我们执行完任务后,service就销毁了
stopSelf(msg.arg1);
}
}
// 在onStart() 方法里发出了消息。
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
注意事项
1.为什么不能通过 bindService启动IntentService?
因为,bindService启动时,就不会执行onStartCommand() 方法,就会导致 OnHandleIntent() 不会被调用,这样一来,就和普通的Service 没什么区别了。
2.为什么多次启动 IntentService 会顺序执行事件?
IntentService 中使用的 Handler、Looper、MessageQueue 机制把消息发送到线程中去执行的,
所以多次启动 IntentService 不会重新创建新的服务和新的线程,只是把消息加入消息队列中等待执行。
3.停止服务后,后续的事件得不到执行?
如果服务停止,会调用Looper.quit()方法,清除消息队列中的消息,后续的事件就得不到执行了。
@Override
public void onDestroy() {
mServiceLooper.quit();
}