内容简介:本人只是 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();
}
复制代码
在这里会停止工作线程的消息循环,等待线程退出。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
perl进阶
Randal L.Schwartz、brian d.foy、Tom Phoenix / 韩雷 / 人民邮电出版社 / 2015-10-1 / 69
本书是Learning Perl一书的进阶。学完本书之后,您可以使用Perl语言的特性编写从简单脚本到大型程序在内的所有程序,正是Perl语言的这些特性使其成为通用的编程语言。本书为读者深入介绍了模块、复杂的数据结构以及面向对象编程等知识。 本书每章的篇幅都短小精悍,读者可以在一到两个小时内读完,每章末尾的练习有助于您巩固在本章所学的知识。如果您已掌握了Learning Perl中的内容并渴......一起来看看 《perl进阶》 这本书的介绍吧!