什么是IntentService及特点
IntentService是一种特殊的Service,是继承于Service并且是一个抽象类。
- IntentService可用于执行后台耗时任务,当任务执行完后会自动停止销毁
- 由于IntentServce是继承Service的原因,它优先级比普通线程高很多,可以执行一些高优先级的后台任务,并且不会轻易被系统进程杀死
- IntentService内部是通过HandlerThread和Handler实现异步操作的
- IntentSerivce使用比较简单,只需实现onHandlerIntent方法与构造函数,就可以实现异步任务。
IntentService使用方法
DownloadIntentService 类 ,注意service要在AndroidMainfest文件中注册
public class DownloadIntentService extends IntentService {
public static final String TAG = "DownloadIntentService";
/**
* 定义内部接口回调,在子线程中执行
*/
private static UpdateUI mUpdateUI;
private HandlerActivity.IntentServiceReceiver mReceiver;
private LocalBroadcastManager mBroadcastManager;
public interface UpdateUI {
void updateUI(Message message);
}
public static void setUpdateUI(UpdateUI updateUI) {
mUpdateUI = updateUI;
}
/**
* 在构造函数内必须传值,否则会抛出异常
*/
public DownloadIntentService() {
super("test");
}
/**
*
*/
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//模拟网络请求等待
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int result = 0;
if (intent != null) {
result = intent.getExtras().getInt(TAG);
}
Message message = Message.obtain();
message.what = result;
//通过接口回调的方式,把结果返回到activity,也可通过广播的形式回传
if (mUpdateUI != null) {
mUpdateUI.updateUI(message);
}
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
//动态注册本地广播
// mBroadcastManager = LocalBroadcastManager.getInstance(this);
// IntentFilter intentFilter = new IntentFilter();
//intentFilter.addAction("com.hzw.receiver.LOCAL_BROADCAST");
// mReceiver = new HandlerActivity.IntentServiceReceiver();
//mBroadcastManager.registerReceiver(mReceiver, intentFilter);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Log.d(TAG, "onStart: ");
super.onStart(intent, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: ");
return super.onBind(intent);
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind: ");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: ");
super.onDestroy();
}
}
Activity类部分代码
Intent intent = new Intent(this, DownloadIntentService.class);
//循环多次启动了service,其实只创建一个Service实例
for (int i = 0; i <5 ; i++) {
intent.putExtra(DownloadIntentService.TAG,i);
startService(intent);
}
DownloadIntentService.setUpdateUI(new DownloadIntentService.UpdateUI() {
//必须通过handler更新UI,此方法是异步方法
@Override
public void updateUI(Message message) {
//通知主线程更新UI
mServiceHanlder.sendMessageAtTime(message,1000);
}
});
-----------------------------------------------------------------
private Handler mServiceHanlder=new Handler(){
@Override
public void handleMessage(Message msg) {
mTvContent.setText(String.valueOf(msg.what));
}
};
使用IntentService需要注意构造方法内必须传入值实现,否则会抛出异常的,另外一个就是onHandleThread是异步方法,在通过接口回调到Activity时,需要同Handler来更新UI。在代码中我们循环多次启动service服务,并不会创建多个实例,只有一个service实例,这和传统的Service是一样的。当我们循环多次启动service,是不是会把之前的结果覆盖呢?其实是不会的,因为IntentServie内部是Handler+HandlerThread,有自己的Looper对象及消息队列,当我们每启动一次把onHandleThread异步执行的结果插入到消息队列中,然后通过Looper依次从消息队列中取出来。运行以上代码:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onCreate:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStartCommand:
03-10 15:21:30.549 2474-2474/com.pos.handler D/DownloadIntentService: onStart:
03-10 15:21:35.569 2474-2474/com.pos.handler D/DownloadIntentService: onDestroy:
从以上Log日志打印可以看出,onCreate方法只调用一次,而onStartCommand和onStart方法会调用多次,从而验证了上面所说的多次启动IntentService只会有一个实例,最后当异步任务执行完成后,IntentService会自动销毁。
IntentService源码解析
我们先从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();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
当IntentService一启动,onCreate方法就会被调用,从onCreate方法可以看出,其内部创建了HandlerThread对象(本身就是工作线程,有异步能力),接着启动了线程,然后把通过HandlerThread的getLooper方法获取Looper对象,并把HandlerThread持有的异步线程Looper对象传入ServiceHanlder对象(继承Handler)中,从而ServiceHandler内部就有异步线程的Looper对象,这样ServiceHandler对象就有了执行异步任务的能力。
上面分析了ServiceHandler持有异步线程,那IntentService是怎么启动异步任务的,接下来分析onStartComand和onStart方法:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = 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;
}
当onCreate方法被调用后,接下来会执行onStartCommand方法,在onStartCommand内又会调用onStart方法,在onStart方法中,会通过mServiceHandler对象发送一个消息到HandlerThread处理并插入到消息队列中,接着HandlerThread中Looper对象会从消息队列中取出来,回传给ServiceHandler对象处理,ServiceHandler会调用handleMessage方法,在其内做异步任务操作,接下来看看mServiceHandler的源码:
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);
}
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
从源码中可以看出handleMessage方法内的onHandleIntent是一个抽象方法,也就是该方法是必须实现的。因ServiceHandler本身就是一个处理异步任务的类(前面已经分析过了),所以onHandleIntent是异步方法,是在工作线程中运行的,当异步任务执行完后,会调用stopSelf(msg.arg1)尝试停止服务。这里采用stopSelf(int startId)而不是stopSelf()来停止服务,是因为stopSelf()会立即停止服务,而stopSelf(int startId)会等待所有消息都处理完后才终止服务。
总结
如果后台任务只有一个,在onHandleIntent内执行异步任务完后,IntentService会自动销毁;如果后台任务有多个,执行完最后一个IntentService的异步任务,才会自动销毁,因为每次执行一个后台异步任务,都会启动一次IntentService,而IntentService内部是通过发消息的方式给HandlerThread处理,会通过Handler中的Looper对象(就是HandlerThread内部的Looper对象)依次从消息队列取出回传给Handler的handleMessage方法处理。也就是说如果后台有多个异步任务,会按照外部的调用顺序依次执行 ,直到最后一个执行完毕后,IntentService才会自动销毁。