💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
#### 11.2.4 IntentService 参考: [扩展 IntentService 类](https://developer.android.google.cn/guide/components/services#ExtendingIntentService) ``` package android.app; import android.annotation.WorkerThread; import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; 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(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } @Override public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onDestroy() { mServiceLooper.quit(); } @Override public IBinder onBind(Intent intent) { return null; } @WorkerThread protected abstract void onHandleIntent(Intent intent); } ``` [IntentService](https://www.androidos.net.cn/android/6.0.1_r16/xref/frameworks/base/core/java/android/app/IntentService.java)是一种特殊的Service,它**继承了Service并且它是一个抽象类**,因此**必须创建它的子类才能使用IntentService**。IntentService可用于**执行后台耗时的任务,当任务执行后它会自动停止**,同时由于IntentService是服务的原因,这导致**它的优先级比单纯的线程要高很多**,所以IntentService**比较适合执行一些高优先级的后台任务,因为它优先级高不容易被系统杀死**。在实现上,**IntentService封装了HandlerThread和Handler**,这一点可以从它的onCreate方法中看出来,如下所示。 ``` @Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } ``` **当IntentService被第一次启动时,它的onCreate方法会被调用,onCreate方法会创建一个HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息最终都会在HandlerThread中执行**,从这个角度来看,**IntentService也可以用于执行后台任务**。 **每次启动IntentService,它的onStartCommand方法就会调用一次,IntentService在onStartCommand中处理每个后台任务的Intent**。 下面看一下**onStartCommand方法是如何处理外界的Intent的**,onStartCommand调用了onStart,onStart方法的实现如下所示。 ``` @Override public void onStart(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(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } ``` 可以看出,**IntentService仅仅是通过mServiceHandler发送了一个消息,这个消息会在HandlerThread中被处理。mServiceHandler收到消息后,会将Intent对象传递给onHandleIntent方法(从该方法的注释可以看出,IntentService被启动后,会调用该方法)去处理**。 注意:**这个Intent对象的内容和外界的startService(intent)中的intent的内容是完全一致的,通过这个Intent对象即可解析出外界启动IntentService时所传递的参数,通过这些参数就可以区分具体的后台任务,这样在onHandleIntent方法中就可以对不同的后台任务做处理了**。 当**onHandleIntent方法执行结束后,IntentService会通过stopSelf(int startId)方法来尝试停止服务**。这里之所以采用stopSelf(int startId)而不是stopSelf()来停止服务,那是因为**stopSelf()会立刻停止服务,而这个时候可能还有其他消息未处理,stopSelf(int startId)则会等待所有的消息都处理完毕后才终止服务。一般来说,stopSelf(int startId)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止服务,不相等则不停止服务,这个策略可以从AMS的stopServiceToken方法的实现中找到依据**,读者感兴趣的话可以自行查看源码实现。ServiceHandler的实现如下所示。 ``` 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); } } ``` IntentService的**onHandleIntent方法是一个抽象方法,它需要我们在子类中实现**,它的**作用是从Intent参数中区分具体的任务并执行这些任务**。 * 如果目前**只存在一个后台任务**,那么onHandleIntent方法**执行完这个任务后,stopSelf(int startId)就会直接停止服务**; * 如果目前**存在多个后台任务**,那么当onHandleIntent方法**执行完最后一个任务时,stopSelf(int startId)才会直接停止服务**。 另外,**由于每执行一个后台任务就必须启动一次IntentService,而IntentService内部则通过消息的方式向HandlerThread请求执行任务,Handler中的Looper是顺序处理消息的,这就意味着IntentService也是顺序执行后台任务的,当有多个后台任务同时存在时,这些后台任务会按照外界发起的顺序排队执行**。 * [ ] 示例 下面通过一个示例来进一步说明IntentService的工作方式,首先派生一个IntentService的子类,比如LocalIntentService,它的实现如下所示。 public class LocalIntentService extends IntentService { private static final String TAG = "LocalIntentService"; public LocalIntentService() { super(TAG); } @Override protected void onHandleIntent(Intent intent) { String action = intent.getStringExtra("task_action"); Log.d(TAG, "receive task :" + action); SystemClock.sleep(3000); if ("com.ryg.action.TASK1".equals(action)) { Log.d(TAG, "handle task: " + action); } } @Override public void onDestroy() { Log.d(TAG, "service destroyed."); super.onDestroy(); } } 这里对LocalIntentService的实现做一下简单的说明。**在onHandleIntent方法中会从参数中解析出后台任务的标识,即task_action字段所代表的内容,然后根据不同的任务标识来执行具体的后台任务**。这里为了简单起见,直接通过SystemClock.sleep(3000)来休眠3000毫秒从而模拟一种耗时的后台任务,**另外为了验证IntentService的停止时机,这里在onDestroy()中打印了一句日志**。LocalIntentService实现完成了以后,就可以在外界请求执行后台任务了,在下面的代码中先后发起了3个后台任务的请求: ``` Intent service = new Intent(this, LocalIntentService.class); service.putExtra("task_action", "com.ryg.action.TASK1"); startService(service); service.putExtra("task_action", "com.ryg.action.TASK2"); startService(service); service.putExtra("task_action", "com.ryg.action.TASK3"); startService(service); ``` 运行程序,观察日志,如下所示。 ``` 05-17 17:08:23.186 E/dalvikvm(25793): threadid=11: calling run(), name= IntentService[LocalIntentService] 05-17 17:08:23.196 D/LocalIntentService(25793): receive task :com.ryg.action.TASK1 05-17 17:08:26.199 D/LocalIntentService(25793): handle task: com.ryg.action.TASK1 05-17 17:08:26.199 D/LocalIntentService(25793): receive task :com.ryg.action.TASK2 05-17 17:08:29.192 D/LocalIntentService(25793): receive task :com.ryg.action.TASK3 05-17 17:08:32.205 D/LocalIntentService(25793): service destroyed. 05-17 17:08:32.205 E/dalvikvm(25793): threadid=11: exiting, name= IntentService[LocalIntentService] ``` 从上面的日志可以看出,**三个后台任务是排队执行的,它们的执行顺序就是它们发起请求对的顺序,即TASK1、TASK2、TASK3**。 另外一点就是**当TASK3执行完毕后,LocalIntentService才真正地停止,从日志中可以看出LocalIntentService执行了`onDestroy()`,这也意味着服务正在停止**。