什么是IntentService?
一个带有工作线程的,并且具有任务完成会自动停止功能的Service
一.IntentService的用法
//继承IntentService,并取个名儿
class SampleIntentService : IntentService("SampleIntentService") {
//重写onHandleIntent
override fun onHandleIntent(intent: Intent?) {
//进行耗时操作,这里是工作线程
}
//别忘了在mainfest里注册哦
}
emmmm,IntentService就这么简单,不过这只是用法哦。
二.IntentService结构组成
要想了解源码,别单单看别人的技术文章,看是没有用的,最好把源码打开,边看边对着源码了解,那样能理解的快些。
1.看看继承类
这里看到IntentService是继承Service
public abstract class IntentService extends Service
2.看看构造方法
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
这里可以看到刚才为嘛给IntentService带个String的参数了,原来给是工作线程取名字呀
public IntentService(String name) {
super();
mName = name;
}
3.因为是继承Service的,所以我们可以看看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();
//这里创建工作线程,所以使用intentService为什么不需要创建工作线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//获取looper,与handler产生联动,实现消息的通信
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
这里小结下(IntentService里有什么东西)
1.创建了一个具有looper的工作线程
2.创建了一个线程通信的Handler
3.把具有looper的线程跟handler联动
三.IntentService具体实现
当一个IntentService开启时,先调用onCreate方法,然后会调用onStartCommand(),然后调用onStart(),储存message,handler发送消息,handleMessage()处理消息,然后onHandleIntent交给子类去实现,等message都处理完了,stopSelf(msg.arg1)停止服务
//继承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);
}
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId; //这里要注意,储存这个startId是有用的,后面会讲到
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@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();
}
这里有个关键,每次start(),都会把message存储到messagequeue队列中,messagequeue是单线程队列,那么intentService是怎么知道任务全部完成才会去取消任务的呢?
可以看看ActiveServices源码
关键代码
boolean stopServiceTokenLocked(ComponentName className, IBinder token,
int startId) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className
+ " " + token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
if (r != null) {
if (startId >= 0) {
// Asked to only stop if done with all work. Note that
// to avoid leaks, we will take this as dropping all
// start items up to and including this one.
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
while (r.deliveredStarts.size() > 0) {
ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
cur.removeUriPermissionsLocked();
if (cur == si) {
break;
}
}
}
if (r.getLastStartId() != startId) {
return false;
}
if (r.deliveredStarts.size() > 0) {
Slog.w(TAG, "stopServiceToken startId " + startId
+ " is last, but have " + r.deliveredStarts.size()
+ " remaining args");
}
}
synchronized (r.stats.getBatteryStats()) {
r.stats.stopRunningLocked();
}
r.startRequested = false;
if (r.tracker != null) {
r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
r.callStart = false;
final long origId = Binder.clearCallingIdentity();
bringDownServiceIfNeededLocked(r, false, false);
Binder.restoreCallingIdentity(origId);
return true;
}
return false;
}
ActiveServices里的stopServiceTokenLocked()里的判断r.getLastStartId()!= startId,来判断当前startId是不是最后一个startId,是就执行r.stats.stopRunningLocked()来终止
课外知识
Handler是负责线程间的通信的
HandlerThread是什么呢?简单看看介绍(这个类蛮重要的 ,想要了解大家可以去查查资料,原理也不难)
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
是一个拥有looper的线程类,这个looper可以用来跟handler来互动,但一定要用start方法来开启
网友评论