目录:
1. 前言
本文是对 IntentService 的深入学习,包含其基本使用方法、IntentService更新处理UI工作,以及对 IntentService 的源码分析。
1.1 定义
IntentService 是 Service 的子类,继承于 Service 类,用于处理后台异步请求任务。
用户通过调用 Context.StartService(Intent) 发送请求,服务根据请求启动,使用工作线程依次处理每个 Intent任务请求,并在处理完所有任务请求后自身停止服务。
使用时,扩展 IntentService ,即实现它的子类并具体实现 onHandleIntent(android.content.Intent) 方法。IntentService 接收 Intent,启动工作线程,并在适当时机停止服务。
所有的请求都在同一个工作线程上处理,一次处理一个请求,所以处理完所以的请求可能会花费很长的时间,但由于 IntentService 是另外创建的线程来工作,所以保证不会阻止App 的主线程,防止 App 出现 ANR。
1.2 使用场景
用于处理后台长时间的耗时操作,如:下载文件、播放音乐...
2. 使用方法
由于 IntentService 是抽象类,所以在实际使用中,我们需要创建一个 IntentService 子类来具体实现。
使用步骤分为两步:
- 创建 IntentService 子类,并在清单文件中注册。
- 在 Activity 中通过调用 startService(Intent) 方法发送任务请求。
例子:
我们模拟在后台进行下载以及读取文件的耗时操作,观察打印出来的 Log 信息。
如下所示:
IntentService 的执行流程为:onCreate() -> onStartCommand() -> onStart() -> onHandleIntent -> ···处理完所有请求··· -> onDestroy()
具体代码如下所示:分 Java & Kotlin 两个版本展示。
2.1 Java版本
步骤一:创建 MyIntentService
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public static final String DOWNLOAD_ACTION = "DOWNLOAD_ACTION";
public static final String READ_ACTION = "READ_ACTION";
public static final String TEST_AUTHOR = "TEST_AUTHOR";
public MyIntentService() {
super("MyIntentService");
}
/**
* 进行一些耗时操作
* @param intent 通过startService(Intent intent)方法传入
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.e(TAG, "onHandleIntent: ");
if (intent != null) {
final String action = intent.getAction();
String author = intent.getExtras().getString(TEST_AUTHOR);
//模拟下载动作
if (DOWNLOAD_ACTION.equals(action)) {
for (int i = 0; i < 5; i++) {
try {
//线程等待1s,模拟耗时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, author + " " + action + " " + i);
}
}
//模拟读操作
if (READ_ACTION.equals(action)) {
for (int i = 0; i < 5; i++) {
try {
//线程等待2s,模拟耗时操作
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, author + " " + action + " " + i);
}
}
}
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onCreate: ");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
super.onStart(intent, startId);
Log.e(TAG, "onStart: ");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: ");
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
}
}
并记得在清单文件中注册,这一步你也可以通过 Android Studio 来帮我们完成
<service
android:name=".intentservice.MyIntentService"
android:exported="false">
</service>
步骤二:通过 startService(Intent) 发送任务请求
public class IntentServiceActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
//模拟 Jere 做下载动作
Intent intent = new Intent(this, MyIntentService.class);
intent.setAction(MyIntentService.DOWNLOAD_ACTION);
intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere");
startService(intent);
//模拟 James 做读取动作
Intent jamesIntent = new Intent(this, MyIntentService.class);
jamesIntent.setAction(MyIntentService.READ_ACTION);
jamesIntent.putExtra(MyIntentService.TEST_AUTHOR, "James");
startService(jamesIntent);
}
}
2.2 Koltin版本
步骤一:创建 MyIntentService
class MyIntentService : IntentService("MyIntentService") {
companion object {
private val TAG: String = "MyIntentService"
val DOWNLOAD_ACTION = "DOWNLOAD_ACTION"
val READ_ACTION = "READ_ACTION"
val TEST_AUTHOR = "TEST_AUTHOR"
}
override fun onHandleIntent(intent: Intent?) {
val action: String? = intent?.action
val author: String? = intent?.extras?.getString(TEST_AUTHOR)
when (intent?.action) {
DOWNLOAD_ACTION -> {
for (i in 0..10) {
Thread.sleep(1000)
Log.e(TAG, "$author $action $I")
}
}
READ_ACTION -> {
for (j in 0..10) {
Thread.sleep(2000)
Log.e(TAG, "$author $action $j")
}
}
}
}
override fun onCreate() {
super.onCreate()
Log.e(TAG, "onCreate")
Toast.makeText(this, "conCreate", Toast.LENGTH_SHORT).show()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e(TAG, "onStartCommand")
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show()
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
Log.e(TAG, "onDestroy")
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show()
}
}
在清单文件中注册:
<service
android:name=".multiplethread.intentservice.MyIntentService"
android:exported="false">
</service>
步骤二:通过 startService(Intent) 发送任务请求
class TestIntentServiceActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_intent_service)
val intent = Intent()
intent.setClass(this, MyIntentService::class.java)
intent.action = MyIntentService.DOWNLOAD_ACTION
intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere")
startService(intent)
val jamesIntent = Intent()
jamesIntent.setClass(this, MyIntentService::class.java)
jamesIntent.action = MyIntentService.READ_ACTION
jamesIntent.putExtra(MyIntentService.TEST_AUTHOR, "James")
startService(jamesIntent)
}
}
2.3 IntentService更新处理UI工作
思考: 在上面的例子中,我们是通过在打印出来的日志信息来观察后台异步任务的执行情况,那 IntentService 可以处理 UI 工作吗?
答: IntentService 是服务端,肯定是不可以处理 UI 工作的,但是他可以通过其对应的客户端,也就是 Activity 来更新处理 UI 工作。
客户端与服务端之间的通信,我们使用 Messenger ,关于 Messenger 内容请看另一篇博客 Android Messenger初探,具体实现如下所示:
例子: 我们在 IntentService 模拟下载任务,通过 ProgressBar 显示下载进度。
效果图如下所示:
具体代码如下所示:分Java & Kotlin 两个版本展示。
2.3.1 Java版本
- 在 Activity 中发送请求时,新建一个 Messenger 对象,传递给 IntentService。
public class IntentServiceActivity extends AppCompatActivity {
private ProgressBar downloadProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
downloadProgressBar = findViewById(R.id.download_progress_bar);
//用于创建 Messenger,接收 IntentService 回复的消息
MessengerHandler messengerHandler = new MessengerHandler(this);
//模拟 Jere 做下载动作
Intent intent = new Intent(this, MyIntentService.class);
intent.setAction(MyIntentService.DOWNLOAD_ACTION);
intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere");
//将 Messenger 传递给 IntentService,让其回复消息回来
intent.putExtra(MyIntentService.TEST_MESSENGER, new Messenger(messengerHandler));
startService(intent);
}
/**
* 用于创建 Messenger 对象
*
* 静态内部类,防止内存泄漏
*/
public static class MessengerHandler extends Handler {
private WeakReference<IntentServiceActivity> weakReference;
MessengerHandler(IntentServiceActivity activity) {
weakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//msg 为 IntentService 回复的消息,包含 Bundle 等信息。
Bundle bundle = msg.getData();
//获取 IntentService 传递过来的 下载进度 参数
int downloadProgressBarValue = bundle.getInt(MyIntentService.DOWNLOAD_PROGRESS_VALUE_KEY);
//将下载进度设置成 ProgressBar 的进度,显示出来。
IntentServiceActivity activity = weakReference.get();
if (activity != null && !activity.isFinishing()) {
activity.downloadProgressBar.setProgress(downloadProgressBarValue);
}
}
}
}
- 在 IntentService 中获取 Messenger 对象,并回复消息给 Activity。
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public static final String DOWNLOAD_ACTION = "DOWNLOAD_ACTION";
public static final String READ_ACTION = "READ_ACTION";
public static final String TEST_AUTHOR = "TEST_AUTHOR";
public static final String TEST_MESSENGER = "TEST_MESSENGER";
public static final String DOWNLOAD_PROGRESS_VALUE_KEY = "DOWNLOAD_PROGRESS_VALUE";
public MyIntentService() {
super("MyIntentService");
}
/**
* 进行一些耗时操作
* @param intent 通过startService(Intent intent)方法传入
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.e(TAG, "onHandleIntent: ");
if (intent != null) {
final String action = intent.getAction();
String author = intent.getExtras().getString(TEST_AUTHOR);
//模拟下载动作
if (DOWNLOAD_ACTION.equals(action)) {
for (int i = 0; i <= 6; i++) {
try {
//线程等待1s,模拟耗时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, author + " " + action + " " + i);
//获取从 Activity 传入的 Messenger
Messenger messenger = (Messenger) intent.getExtras().get(TEST_MESSENGER);
//新建消息,设置下载进度参数
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putInt(DOWNLOAD_PROGRESS_VALUE_KEY, i);
msg.setData(bundle);
try {
//回复消息
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onCreate: ");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
super.onStart(intent, startId);
Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onStart: ");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: ");
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
}
}
这样就实现了 IntentService 更新处理 UI 工作,具体效果看上图 IntentService更新处理UI工作。
2.3.2 Kotlin版本
同样,Kotlin的实现方式为:
- 在 Activity 中发送请求时,新建一个 Messenger 对象,传递给 IntentService。
class TestIntentServiceActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_intent_service)
val intent = Intent()
intent.setClass(this, MyIntentService::class.java)
intent.action = MyIntentService.DOWNLOAD_ACTION_KEY
intent.putExtra(MyIntentService.TEST_AUTHOR_KEY, "Jere")
//将 Messenger 传递给 IntentService, 使其传递消息回来,实现客户端与服务端之间进行沟通
intent.putExtra(MyIntentService.TEST_MESSENGER_KEY, Messenger(MessengerHandler(this)))
startService(intent)
}
/**
* 此 Handler 用于创建 Messenger 对象,接收 IntentService 回复回来的消息
*
* 静态内部类,防止内存泄漏
*/
class MessengerHandler(activity: TestIntentServiceActivity) : Handler() {
var weakReference: WeakReference<TestIntentServiceActivity> = WeakReference(activity)
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
//msg 为 IntentService 回复的消息,包含 Bundle 等信息。
val bundle: Bundle = msg.data
//获取 IntentService 传递过来的 下载进度 参数
val downloadProgressBarValue: Int =
bundle.get(MyIntentService.DOWNLOAD_PROGRESS_BAR_VALUE_KEY) as Int
val activity: TestIntentServiceActivity? = weakReference.get()
//将下载进度设置成 ProgressBar 的进度,显示出来。
if (activity != null && !activity.isFinishing) {
activity.intentServiceDownloadProgressBar.progress = downloadProgressBarValue
}
}
}
}
- 在 IntentService 中获取 Messenger 对象,并回复消息给 Activity。
class MyIntentService : IntentService("MyIntentService") {
companion object {
private val TAG: String = "MyIntentService"
val DOWNLOAD_ACTION_KEY = "DOWNLOAD_ACTION"
val READ_ACTION_KEY = "READ_ACTION"
val TEST_AUTHOR_KEY = "TEST_AUTHOR"
val TEST_MESSENGER_KEY = "TEST_MESSENGER"
val DOWNLOAD_PROGRESS_BAR_VALUE_KEY = "DOWNLOAD_PROGRESS_BAR_VALUE"
}
override fun onHandleIntent(intent: Intent?) {
val action: String? = intent?.action
val author: String? = intent?.extras?.getString(TEST_AUTHOR_KEY)
when (intent?.action) {
DOWNLOAD_ACTION_KEY -> {
for (i in 0..6) {
Thread.sleep(1000)
Log.e(TAG, "$author $action $I")
//获取从 Activity 中传入的 Messenger 对象
val messenger: Messenger = intent.extras?.get(TEST_MESSENGER_KEY) as Messenger
//新建一个 Message 对象
val msg: Message = Message()
//为 Message 对象设置 下载进度 参数
val bundle: Bundle = Bundle()
bundle.putInt(DOWNLOAD_PROGRESS_BAR_VALUE_KEY, i)
msg.data = bundle
//Messenger 回复消息给 Activity
messenger.send(msg)
}
}
READ_ACTION_KEY -> {
for (j in 0..10) {
Thread.sleep(2000)
Log.e(TAG, "$author $action $j")
}
}
}
}
override fun onCreate() {
super.onCreate()
Log.e(TAG, "onCreate")
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e(TAG, "onStartCommand")
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show()
return super.onStartCommand(intent, flags, startId)
}
override fun onStart(intent: Intent?, startId: Int) {
super.onStart(intent, startId)
Log.e(TAG, "onStart")
Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show()
}
override fun onDestroy() {
super.onDestroy()
Log.e(TAG, "onDestroy")
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show()
}
}
具体效果看上图 IntentService更新处理UI工作。
3. 源码分析
上面介绍了 IntentService 的使用方法,接下来,我们来看一下 IntentService 的源码。如果你理解了 Hander、Looper、MessageQueue三者之间的关系,那么理解 IntentService 的源代码十分容易。(如果不理解,请看博客 Android Handler深入学习(源码分析))
根据上面的例子,我们知道了 IntentService 的执行顺序为:
onCreate() -> onStartCommand() -> onStart() -> onHandleIntent -> ···处理完所有请求··· -> onDestroy()
IntentService 源码如下:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
//创建一个内部类,继承于 Handler 类。
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 构造函数,在你的子类构造函数中调用(在子类中通过 super(name) 方法调用)
*
* @param 参数 name 用于命名工作线程
*
*/
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
super.onCreate();
//创建一个 HandlerThread 对象
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
//启动 HandlerThread 线程
thread.start();
//获取 HandlerThread 中创建的 Looper 对象,赋值给全局变量 mServiceLooper。
mServiceLooper = thread.getLooper();
//创建一个 Handler 对象,并关联刚刚通过 HandlerThread 创建的 Looper 对象,即关联 mServiceLooper
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
//发送消息给 mServiceHanlder,
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* 你不应该在你的 IntentService 类中复写 onStartCommand() 方法。
* 相反,你应该复写 onHandleIntent() 方法,该方法会在 IntentService 接收到启动请求时被调用。
*/
@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() {
//退出 Looper 消息循环
mServiceLooper.quit();
}
/**
* 除非是绑定服务,否则你不需要实现此方法,因为此方法的默认实现返回 null.
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* 此方法在工作线程中被调用用于处理请求,一次只能处理一个请求,处理工作运行于独立于其他应用程序的工作线程中。
* 因此,如果该段代码花费了很长的一段时间,它会阻塞同一个 IntentService 的其他请求,但不会阻塞其他任何东西。
* 当所有的请求都被处理完,该 IntentService 就会停止运行,所以你不用调用 stopSelf() 方法。
*
* @param intent 通过 startService(Intent) 方法传入。如果服务在其进程消失后重新启动,则此值可能为空;
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
总结:
- 在 onCreate() 方法中,我们新建一个 HandlerThread 对象,然后启用它,获取其创建的 Looper 对象,然后新创建一个 Looper 对象关联该 Looper 对象。关于 HandlerThread 的知识点请看另一篇博客 Android HandlerThread详解(源码分析)
- 然后我们在 onStart() 方法中,通过 Message,将 Intent任务请求 发送给 mServiceHandler,Intent任务请求就是我们在 Activity 中通过 startService(Intent) 传入的 Intent。
- mServiceHanlder 接受到任务请求,调用 onHandleIntent() 方法处理任务请求,处理完所有请求后,调用 stopSelf() 结束 IntentService。
至此 HandlerThread 的源码也就分析结束了。
其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。
另外,如果你觉得文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!