IntentService源码分析
来源:互联网 发布:智慧的云计算 pdf 编辑:程序博客网 时间:2024/06/01 18:00
前言
在Android中,Service是运行在主线程之中的。如果要在Service中执行耗时的任务,那么我们需要手动创建子线程。并且,在任务完成的时候,我们需要手动停止Service。为了简化这些操作,Android提供了一个IntentService类。IntentService是Service的子类,它使用了一个HandlerThread线程来依次处理每个启动Service的请求,并在所有的请求都处理完毕之后自动停止Service。
基础知识
IntentService是一个Service,我们需要熟悉Service的生命周期,具体可以阅读 Service的生命周期 这篇文章。
IntentService内部使用了一个HandlerThread线程,我们需要熟悉HandlerThread的工作原理,具体可以阅读 HandlerThread源码分析 这篇文章。
基本用法
首先,我们需要写一个继承自IntentService的类,并实现 onHandleIntent() 抽象方法。IntentService没有默认的构造方法,所以我们还需要声明一个默认的构造方法。示例代码如下所示:
public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { // execute your task }}
其中,构造方法调用了super()方法,它用来命名IntentService内部的HandlerThread线程名。onHandleIntent()方法是在HanderThread线程中执行的,我们可以直接在该方法中执行耗时的任务。
然后,我们就可以在其它的组件(比如,Activity和BroadcastReceiver)中调用startService()方法来启动该IntentService了。示例代码如下所示:
Intent intent = new Intent(this, MyIntentService.class);startService(intent);
最后,别忘了要在AndroidManifest.xml文件中注册该IntentService类。示例代码如下所示:
<application ... <service android:name=".MyIntentService" android:exported="false" /></application>
源码分析
IntentService是一个继承自Service的抽象类,它声明了一个onHandleIntent()抽象方法。
public abstract class IntentService extends Service { ... @WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent);}
首先,我们来看IntentService的构造方法。
public IntentService(String name) { super(); mName = name;}
构造方法必须被子类的构造方法所调用。它保存了一个字符串在mName成员变量中,用来命名IntentService内部的HandlerThread线程名。
当我们在其它的组件(比如,Activity和BroadcastReceiver)中调用startService()方法来启动Service时,如果Service还没有创建,那么系统将创建Service并回调Service的onCreate()方法。所以,接下来我们来看IntentService的onCreate()方法。
@Overridepublic void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper);}
在onCreate()方法中,IntentService创建了一个HanderThread线程,并启动了该线程。接着,它获取了该线程的Looper,并使用该Looper创建了一个与该线程相关联的Handler。这样,IntentService就可以通过该Handler来控制HandlerThread线程执行耗时的任务。
回调onCreate()方法之后,系统将回调Service的onStartCommand()方法。所以,接下来我们来看IntentService的onStartCommand()方法。
@Overridepublic int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}
onStartCommand()方法调用了onStart()方法。
@Overridepublic void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg);}
在onStart()方法中,IntentService使用了与HandlerThread线程相关联的Handler发送了一条Message。因此,其它的组件每次调用startService()方法来启动Service时,IntentService都会发送一条Message给HandlerThread线程。
HandlerThread线程的Looper从MessageQueue中循环地取出Message进行处理。最终Message是在与HandlerThread线程相关联的Handler中进行处理的。所以,接下来我们来看与HandlerThread线程相关联的Handler是如何处理Message的。
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()方法被调用。因为该Handler是与HandlerThread线程相关联的,所以onHandleIntent()方法是在HandlerThread线程中执行的,我们可以直接在该方法中执行耗时的任务。通过Message中Intent,我们可以区分不同的启动Service请求。因为Looper是从MessageQueue中循环地取出Message进行处理的,所以IntentService是以队列的方式来处理多个启动Service的请求。
在handleMessage()方法的最后调用了Service的stopSelf()方法来自动停止Service。启动Service的启动ID被传递给stopSelf()方法,以确保处理完最后一次启动Service的请求之后才停止Service。
在停止Service时,系统会回调Service的onDestroy()方法。所以,最后我们来看IntentService的onDestroy()方法。
@Overridepublic void onDestroy() { mServiceLooper.quit();}
在onDestroy()方法中,IntentService调用了与HandlerThread线程相关联的Looper的quit()方法。quit()方法退出了HandlerThread线程的Looper消息循环,结束了HandlerThread线程。
总结
IntentService是Service的子类,它使用了一个HandlerThread线程来依次处理每个启动Service的请求,并在所有的请求都处理完毕之后自动停止Service。
例子
接下来举一个简单的例子来实践IntentService。项目源码地址:https://github.com/chongyucaiyan/ServiceDemo
首先,新建一个继承自IntentService的类。具体的代码和注释如下所示:
package com.github.cyc.intentservice;import android.app.IntentService;import android.content.Intent;import android.util.Log;/** * Created by cyc on 2017/9/24. */public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService"; // Action public static final String ACTION_DO_TASK1 = "com.github.cyc.intentservice.MyIntentService.do_task1"; public static final String ACTION_DO_TASK2 = "com.github.cyc.intentservice.MyIntentService.do_task2"; public MyIntentService() { // 指定HandlerThread线程名 super("MyIntentService"); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate(), current thread is " + Thread.currentThread().getName()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand(), current thread is " + Thread.currentThread().getName()); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { Log.i(TAG, "onHandleIntent(), current thread is " + Thread.currentThread().getName()); if (ACTION_DO_TASK1.equals(intent.getAction())) { // 执行任务1 doTask1(); } else if (ACTION_DO_TASK2.equals(intent.getAction())) { // 执行任务2 doTask2(); } } } private void doTask1() { Log.i(TAG, "doTask1(), start"); // 模拟耗时任务 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "doTask1(), end"); } private void doTask2() { Log.i(TAG, "doTask2(), start"); // 模拟耗时任务 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "doTask2(), end"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy(), current thread is " + Thread.currentThread().getName()); }}
我们在onCreate()、onStartCommand()、onHandleIntent()和onDestroy()方法中打印了当前线程的名字。在onHandleIntent()方法中,我们根据Intent的Action来区分具体执行哪个耗时任务。
然后,我们在MainActivity页面中放置了两个按钮。具体的代码和注释如下所示:
package com.github.cyc.intentservice;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initContentView(); } private void initContentView() { findViewById(R.id.btn_main_start_service1).setOnClickListener(this); findViewById(R.id.btn_main_start_service2).setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_main_start_service1: // 启动Service Intent intent1 = new Intent(this, MyIntentService.class); intent1.setAction(MyIntentService.ACTION_DO_TASK1); startService(intent1); break; case R.id.btn_main_start_service2: // 启动Service Intent intent2 = new Intent(this, MyIntentService.class); intent2.setAction(MyIntentService.ACTION_DO_TASK2); startService(intent2); break; default: break; } }}
当点击Start Service1按钮时,启动Service执行任务1。当点击Start Service2按钮时,启动Service执行任务2。
最后,别忘了要在AndroidManifest.xml文件中注册该IntentService类。具体的代码如下所示:
<application ... <service android:name=".MyIntentService" android:exported="false" /></application>
接下来,我们来运行一下。先点击Start Service1按钮,打印的信息如下图所示:
可以看到,先是创建Service,然后在onHandleIntent()方法中执行任务,最后任务执行完毕自动停止Service。根据打印的线程信息,我们知道onCreate()、onStartCommand()、和onDestroy()方法都是在主线程之中执行的,而onHandleIntent()方法是在HandlerThread线程中执行的。
然后,快速地点击Start Service1和Start Service2按钮各一下,打印的信息如下图所示:
可以看到,启动Service、任务执行、停止Service的过程与上面类似。需要注意的是,任务2是在任务1执行完毕之后才开始执行的,这验证了IntentService是以队列的方式来处理多个启动Service的请求。
参考
- Android 7.1.1 (API level 25)
- https://developer.android.com/reference/android/app/IntentService.html
- https://developer.android.com/guide/components/services.html
- IntentService源码分析
- IntentService源码分析
- IntentService源码分析
- IntentService源码分析
- IntentService源码分析
- IntentService源码分析
- 从源码分析IntentService
- IntentService源码分析
- IntentService源码分析
- IntentService 源码分析
- IntentService 源码分析
- intentservice源码分析
- android-----IntentService源码分析
- IntentService的源码分析
- IntentService源码分析
- IntentService源码分析
- IntentService源码分析
- IntentService源码分析
- Sublime Text 3 绝对神器
- KNN算法
- Ubuntu中虚拟环境pip安装包超时问题
- jvm内存模型
- CVE-2010-2883
- IntentService源码分析
- MySQL索引结构类型划分
- 【Android开发点滴】解决安卓6.0以上版本不能读取外部存储权限的问题
- 基于iOS的网络音视频实时传输系统(一)- 前言
- Android UI绘制
- hadoop笔记本
- CentOS7 Hbase-1.3.1 分布式部署
- Oracle dblink 同义词 表赋权
- 王者荣耀英雄分析--孙悟空