十、IntentService解析
2021-10-15 本文已影响0人
木小伍
intentService是Android里面的一个封装类,继承自Service,用于异步请求,实现多线程。
工作流程:
intentService工作流程
如果启动IntentService多次,那么每个耗时操作那么每个耗时操作则以队列的形式在intentService的onHandleIntent回调方法中依次执行,执行完自动结束。
1.实现步骤
- 定义IntentService的子类:传入线程名称、复写onHandleIntent方法。
- 2.在Manifest文件中注册
- 3.在Activity中启动Service服务。
2.具体实例
- 定义IntentService的子类
public class MyIntentService extends IntentService {
/**
* 构造函数,传入的参数是工作线程的名称
* @param
*/
public MyIntentService() {
super("wyw");
}
//实现耗时任务
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//根据intent的不同,进行不同的事务处理
String taskName = intent.getExtras().getString("taksName");
switch (taskName){
case "taks1":
Log.i("MyIntentService", "task1");
break;
case "task2":
Log.i("MyIntentService", "task2");
break;
case "task3":
Log.i("MyIntentService", "task3");
break;
}
}
}
- 在manifest文件中注册:
<service android:name=".MyIntentService">
<intent-filter>
<action android:name="com.wyw.service"/>
</intent-filter>
</service>
- 在activity中启动
Intent intent = new Intent("com.wyw.service");
Bundle bundle = new Bundle();
bundle.putString("taskName","task1");
intent.putExtras(bundle);
startService(intent);
Intent intent2 = new Intent("com.wyw.service");
Bundle bundle2 = new Bundle();
bundle.putString("taskName","task2");
intent2.putExtras(bundle2);
startService(intent2);
startService(intent); //多次启动
运行结果
多次启动IntentService结果
3.源码分析
-
IntentService如何单独开启一个新的工作线程?
//IntentService onCreate()方法
@Override
public void onCreate() {
//HandlerThread继承自Thread,内部封装了Looper
//通过实例化HandlerThread新建线程并启动
//所以使用IntentService时不需要额外新建线程
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//获得工作线程的Looper,并维护自己的工作队列
mServiceLooper = thread.getLooper();
//新建Hanler属于工作线程
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
//IntentService的handleMessage方法把接收的消息交给onHandleIntent()处理。
//onHandleIntent()是一个抽象方法,使用时需要重写的方法。
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
-
IntentService如何通过onStartCommand()传递给服务intent被依次插入到工作队列中?
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
//把intent参数包装到message的obj中,然后发送消息,即添加到消息队列中
//这里的intent就是启动服务时startService(Intent)的intent。
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();
}
-
总结
从源码可以看出,IntentService本质是采用Handler & HandlerThread方式:- 通过HandlerThread单独开启一个名为IntentService 的线程。
- 创建一个名叫ServiceHandler的Handler。
- 把内部Handler与HandlerThread所对应的子线程进行绑定
- 通过onStartCommand()传递给服务intent,依次插入到工作队列中,并逐个发送给onHandleIntent()。
- 通过onHandleIntent()来依次处理所有Intent请求对象所对应的任务。
因此我们通过复写onHandleIntent(),再根据Intent的不同进行不同进行不同的现场操作就可以了。
注意:工作任务队列是顺序执行的。
如果一个任务正在IntentService中执行,此时你再发送一个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕才开始执行。
原因:
- 由于onCreate()方法只会调用一次,所以只会创建一个工作线程;
- 当多次调用startService(Intent)时(onStartCommand也会调用多次)其实并会创建新的工作线程,只是把消息加入消息队列中等待执行,所以多次启动IntentService会按照顺序执行。
- 如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。
4.使用场景
- 线程任务需要顺序、在后台执行的使用场景(离线下载)
- 由于所有的任务都在同一个Thread looper里面来做,所以不符合多个数据同时请求的场景。