内容简介:本人只是 Android小菜一个,写技术文档只是为了总结自己在最近学习到的知识,从来不敢为人师,如果里面有些不正确的地方请大家尽情指出,谢谢!其实
本人只是 Android小菜一个,写技术文档只是为了总结自己在最近学习到的知识,从来不敢为人师,如果里面有些不正确的地方请大家尽情指出,谢谢!
1.概述
service
的作用相信大家都是非常熟悉的,主要用来在后台进行任务处理,例如后台播放音乐、下载文件、上传文件等等。由于 service
是运行在主线程中的,也有一定的时间限制,如果在主线程中对一个任务的处理时间超过了限制,进程就会出现“应用不响应”,即 ANR, Application Not Responding
。为了避免这样情况,都会在 service
里用新的 thread
处理一些可能需要更多处理时间的任务。
其实 Android
早就替我们设计了一种更方便的 service + thread
模式,就是本文要讲的 IntentService
,通过它可以很方便地实现在 service
中使用 thread
进行耗时任务的处理。
本文将首先给大家演示下它的基本使用方式,再讲解下 IntentService
的内部原理。
2. IntentService 的使用
在知道如何使用前,先看看 IntentService
到底是什么东西,它的声明如下:
/** * IntentService is a base class for {@link Service}s that handle asynchronous * requests (expressed as {@link Intent}s) on demand. Clients send requests * through {@link android.content.Context#startService(Intent)} calls; the * service is started as needed, handles each Intent in turn using a worker * thread, and stops itself when it runs out of work. * * <p>This "work queue processor" pattern is commonly used to offload tasks * from an application's main thread. The IntentService class exists to * simplify this pattern and take care of the mechanics. To use it, extend * IntentService and implement {@link #onHandleIntent(Intent)}. IntentService * will receive the Intents, launch a worker thread, and stop the service as * appropriate. * * <p>All requests are handled on a single worker thread -- they may take as * long as necessary (and will not block the application's main loop), but * only one request will be processed at a time. */ public abstract class IntentService extends Service { ... } 复制代码
相信大家都能很容易看懂这段声明的意思,小菜在这里简单为大家总结下,这么一大段文字主要是说明了两个问题:
-
IntentService
是什么:用来进行处理异步请求的服务,其内部有一个工作线程,所有发送给服务的请求都会在这个工作线程中按序执行,在处理完所有请求后服务会自动停止。 -
IntentService
如何使用:拓展IntentService
并在其拓展类或者叫子类中实现onHandleIntent(Intent)
接口,在这个接口中进行实际的请求处理,这些请求通过Context.startService(Intent)
来进行发送。
Android SDK
真的可以作为所有 SDK
的典范,它会清楚地告诉你“是什么”和“怎么用”的问题,针对相对复杂的情况,还会直接在声明里给出范例。
既然我们已经知道要如何使用 IntentService
了,就让我们用一个小例子来演示一下:
public class TestIntentService extends IntentService { private static final String TAG = "TestIntentService"; private static final String DEFAULT_NAME = "default_name"; // 为了区分不同的请求和方便调用端使用,直接定义了不同的 ACTION. public static final String DOWNLOAD_ACTION = "com.test.intent.action.DOWNLOAD"; public static final String UPLOAD_ACTION = "com.test.intent.action.UOLOAD"; // 要在 AndroidManifest.xml 里声明 servcie,必须提供一个无参构造函数. public TestIntentService() { // IntentService 的构造函数需要提供一个工作线程的名字信息. super(DEFAULT_NAME); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy"); } @Override public void onHandleIntent(Intent intent) { String action = intent.getAction(); // 根据不同的请求类型进行不同的处理,这里只是休眠一段时间,并没有进行实际的处理。 if (DOWNLOAD_ACTION.equals(action)) { try { Log.i(TAG, "onHandleIntent, start to download"); Thread.sleep(30 * 1000); } catch (InterruptedException ie) { ie.printStackTrace(); } } else if (UPLOAD_ACTION.equals(action)) { try { Log.i(TAG, "onHandleIntent, start to upload"); Thread.sleep(40 * 1000); } catch (InterruptedException ie) { ie.printStackTrace(); } } } } 复制代码
在这段代码里,请求处理函数 onHandleIntent(Intent)
会根据接收到的请求进行不同的处理,如果收到的是“下载”请求就休眠30秒模拟下载过程,如果收到的是“上传”请求就休眠40秒模拟上传过程。在写好了 service
逻辑后一定不要忘记在 AndroidManifest.xml
对其进行注册,否则是无法使用的,注册代码如下:
<service android:name=".TestIntentService" /> 复制代码
注意: 这里只是简单地对其进行注册,并没有设置其他相关属性,例如 intent-filter
,因为这些和本文所讲内容并无直接关系。
请求的接收和处理代码都已完成,接下来就是发送请求的代码逻辑,如下:
// 发送“下载”请求 Intent downloadIntent = new Intent(this, TestIntentService.class); downloadIntent.setAction(TestIntentService.DOWNLOAD_ACTION); startService(downloadIntent); // 发送“上传”请求 Intent upIntent = new Intent(this, TestIntentService.class); upIntent.setAction(TestIntentService.UPLOAD_ACTION); startService(upIntent); 复制代码
现在看当发送这两个“下载”和“上传”请求后, IntentService
是如何响应的:
02-27 12:58:23.100 24190 24190 I TestIntentService: onCreate 02-27 12:58:23.102 24190 24240 I TestIntentService: onHandleIntent, start to download 02-27 12:58:53.107 24190 24240 I TestIntentService: onHandleIntent, start to upload 02-27 12:59:33.115 24190 24190 I TestIntentService: onDestroy 复制代码
可以看到:在发送第一个“下载”请求的时候, service
首先被创建,然后开始处理这个“下载请求”,仅接着第二个“上传”请求也被接收并在处理完第一个请求后开始处理,在处理完所有请求后 service
被自动销毁。
3. IntentService 的原理
前面已经讲了如何通过 IntentService
实现在工作线程中处理较耗时任务,那么 IntentService
内部又是如何实现的呢?本节我们通过分析它的源码来一探究竟。
3.1 创建工作线程
既然 IntentService
的功能是在工作线程中处理任务,首先来看看这个工作线程是如何创建出来的。
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
来完成一些初始化操作:
-
首先创建了一个
HandlerThread
对象,这就是前面一直提到的“工作线程”。大家对Handler
和Thread
都很了解,那这个HandlerThread
是什么呢?简单来说,它就是内部有一个消息循环队列的线程,我们知道默认的线程内部是没有消息循环队列的,这就导致我们无法直接在其内部使用Handler
。Android
为了方便使用,直接提供了一个含有消息循环队列的HandlerThread
。 -
利用已创建的
HandlerThread
内部的消息循环创建一个ServiceHandler
对象,这样它的消息处理函数handleMessage
就会在对应的线程中执行了。
3.2 接收和处理请求
既然工作线程已经创建完成,这时就要考虑如何接收客户端发送过来的请求了,已经了解到客户端是通过 startService
来发送请求的,结合 service
的生命周期,紧接着会执行 onStartCommand
回调:
/** * 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 onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } 复制代码
从这段代码看到, onStartCommand
会直接调用 onStart
,在这里对发送过来的请求接收并通过 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); } } 复制代码
在 handleMessage
中对接收到的请求用 onHandleIntent
进行实际的处理,而 onHandleIntent
就是我们在使用过程中必须实现的处理逻辑。
3.3 销毁工作线程
前面提到:当所有请求都被处理完成后, service
就会被销毁,这是如何实现的呢?在上面看到 handleMessage
方法里在处理完当前请求时会调用 stopSelf(msg.arg1)
来尝试停止当前服务,之所以说“尝试”,是因为它不一定能真正停止服务。还是来看下 stopSelf(int)
的实现代码:
/** * Old version of {@link #stopSelfResult} that doesn't return a result. * * @see #stopSelfResult */ public final void stopSelf(int startId) { if (mActivityManager == null) { return; } try { mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { } } /** * Stop the service if the most recent time it was started was * <var>startId</var>. This is the same as calling {@link * android.content.Context#stopService} for this particular service but allows you to * safely avoid stopping if there is a start request from a client that you * haven't yet seen in {@link #onStart}. */ public final boolean stopSelfResult(int startId) { if (mActivityManager == null) { return false; } try { return mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { } return false; } 复制代码
在 stopSelf(int)
的声明里提到它是 stopSelfResult(int)
的老版本,唯一的区别就是没有返回值。那我们直接看 stopSelfResult(int)
的声明,其中提到只有在当前的 service
的最近一次启动是 startId
发起的才会被停止。把这句话放在 IntentService
的场景里去理解,如果说当前接收到3个请求,在处理第一个请求后打算去停止服务,但是调用 stopSelf()
的时候发现最后一次启动是第三个请求发生的,并不会停止服务;处理完第二个请求后是类似的,只有在处理完第三个请求后,去尝试停止服务,这时发现最近一次启动就是它发起的,可以去停止服务了。停止服务时,其 onDestroy
会得到调用:
@Override public void onDestroy() { mServiceLooper.quit(); } 复制代码
在这里会停止工作线程的消息循环,等待线程退出。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。