android intentservice 实例,IntentService 深度解析(实例 + 源码)

上一篇:

上文说过Service默认工作在当前进程的主线程中,如需执行耗时操作,需要手动开启线程;且一旦开启服务,就会一直运行,直到stopService()或者stopSelf();也就是说我们在线程任务执行完毕后需要手动stopSelf(),才能释放service资源。

android提供了IntentService来实现这个功能,封装了线程,并能够在线程任务执行完毕后,结束service

IntentService的使用

模拟下载一个视频文件的功能:

1、AndroidManifest中注册

复制代码

2、自定义Service继承自IntentService

以下两个方法必须实现,其余是为了探讨IntentService的生命周期,可以自行去掉

实现空参构造方法UpdateService(),super("xx") //xx是定义的线程名

onHandleIntent(),onHandleIntent是在子线程中运行的,可以直接执行耗时操作。

public class UpdateService extends IntentService {

//必须实现,指定线程名

public UpdateService() {

super("customThread");

Log.e("zhen", "UpdateService: customThread" );

}

@Override

public void onCreate() {

super.onCreate();

Log.e("zhen", "UpdateService: onCreate ");

}

@Override

public int onStartCommand(@Nullable Intent intent, int flags, int startId) {

Log.e("zhen", "UpdateService: onStartCommand ");

return super.onStartCommand(intent, flags, startId);

}

@Override

public void onDestroy() {

super.onDestroy();

Log.e("zhen", "UpdateService: onDestroy ");

}

@Override

public void onStart(@Nullable Intent intent, int startId) {

super.onStart(intent, startId);

Log.e("zhen", "UpdateService: onStart ");

}

@Nullable

@Override

public IBinder onBind(Intent intent) {

Log.e("zhen", "UpdateService: onBind ");

return super.onBind(intent);

}

//必须实现,默认在子线程中操作

@Override

protected void onHandleIntent(@Nullable Intent intent) {

Log.e("zhen", "UpdateService: onHandleIntent thread: " + Thread.currentThread().toString());

Log.e("zhen", "开始下载");

int i = 0;

try {

do {

Thread.sleep(2000);

i += 20;

Log.e("zhen", "下载进度: " + i + "% ...");

} while (i < 100);

Log.e("zhen", "下载完成!");

} catch (InterruptedException e) {

e.printStackTrace();

Log.e("zhen", "下载失败!");

}

}

}

复制代码

3、启动service

Intent intent = new Intent(this, UpdateService.class)

startService(intent)

复制代码

IntentService 生命周期

日志打印:

1、点击一次startServiceacf8390eb81d5d0b4a69b7dbaf1accb8.png

构造函数 -> onCreate -> onStartCommand -> onStart -> onHandleIntent -> onDestroy

2、点击两次startServiceebd0b618c09672bae457529a728f3263.png

在onDestroy之前会回调service的 onStartCommand -> onStart

在第一次任务的onHandleIntent执行完毕后,才开始执行第二次任务的onHandleIntent (顺序执行)

所有任务都执行完毕后才执行onDestroy

IntentService源码解析

startService()是由系统来启动service的

1、onCreate()

创建一个名为IntentService[xx]的handlerThread,并启动这个线程

得到这个线程所对应Looper,并根据Looper创建对应的ServiceHandler,来处理message

2、onStartCommand() - > onStart() -> serviceHanlder.sendMessage()

3、通过Looper调度 -> serviceHandler.handleMessage() -> onHandleIntent()(需要子类实现的抽象方法)

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((Intent)msg.obj);

stopSelf(msg.arg1);

}

}

public IntentService(String name) {

super();

mName = name;

}

public void setIntentRedelivery(boolean enabled) {

mRedelivery = enabled;

}

@Override

public void onCreate() {

super.onCreate();

HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");

thread.start();

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

}

@Override

public void onStart(@Nullable Intent intent, int startId) {

Message msg = mServiceHandler.obtainMessage();

msg.arg1 = startId;

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();

}

@Override

@Nullable

public IBinder onBind(Intent intent) {

return null;

}

@WorkerThread

protected abstract void onHandleIntent(@Nullable Intent intent);

}

复制代码

现在可以解释一下多次点击startService的执行过程了

多次点击startService,onCreate只执行一次,但onStartCommand会回调多次,也就是说会通过serviceHandler发送多个message给serviceHandler;

根据Looper.loop(),循环从MessageQueue中取出消息,回调serviceHandler的handleMessage(),也就是说会依次按顺序执行onHandleIntent()

多次启动service不会重新创建新的服务和新的线程,只是把消息加入消息队列中等待执行,而如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。

解答疑惑:

1、为什么不通过bindService()来启动IntentService?

IntentService继承自Service,所以bindService()可以实现正常的service操作;但是上文我们说过通过bindService启动的service不会回调onStartCommand(),也就不会执行start() -> serviceHandler.sendMessage() -> serviceHandler.handleMessage(),这样启动的IntentService将毫无意义。

2、手动stopService怎么执行的?

执行到onDestroy() -> mServiceLooper.quit() -> mQueue.quit(false) -> removeAllMessagesLocked()

MessageQueue.java 循环遍历,清除所有消息

private void removeAllMessagesLocked() {

Message p = mMessages;

while (p != null) {

Message n = p.next;

p.recycleUnchecked();

p = n;

}

mMessages = null;

}

复制代码

3、为什么每次onHanleIntent之后都会执行stopSelf(),为什么不会多次onDestroy() 呢?

因为stopSelf()会进行检查,只有等到所有任务都执行完成后才会真正的destroy

源码解释一波:

IntentService.java # stopSelf(msg.arg1)

//多次点击的startId是从1开始递增

Service.java # stopSelf(int startId)

ActivityManagerService.java # stopServiceToken(ComponentName className, IBinder token, int startId)

复制代码

ActiveServices.java

boolean stopServiceTokenLocked(ComponentName className, IBinder token,

int 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; //就是这里啦。。。。。。

}

}

//省略部分代码

return true;

}

return false;

}

复制代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值