一 概述

我们知道,在Android开发中,遇到耗时的任务操作时,都是放到子线程去做,或者放到Service中去做,在Service中开一个子线程来执行耗时操作。

那么,在Service里面我们需要自己管理Service的生命周期,何时开启何时关闭,还是很麻烦的,还好Android给我们提供了一个这样的类,叫做IntentService

那么IntentService是做什么用的呢?

IntentService: 是继承于Service的一个类,用来处理异步请求。可以直接通过startService(Intent intent)来提交请求,Service的创建,关闭,开子线程等工作,IntentService内部都帮我们封装好了,我们只需要发请求处理请求就行了。

如此简单

我们先来看一下IntentService的用法

二 IntentService用法

假如我们现在有一个下载文件的需求,我们需要开启一个Service并在里面开启一个子线程中去下载文件。

1 先继承IntentService实现一个类,我们叫做 DownloadService如下

public class DownloadService extends IntentService {

     //重写无参的构造方法
public DownloadService(){
super("DownloadService");
} @Override
protected void onHandleIntent(Intent intent) {
String url = intent.getStringExtra("url");
downloadFile(url);
} //下载文件
private void downloadFile(String url){
try {
Log.e("DownloadService","当前线程名:" + Thread.currentThread().getName());
Log.e("DownloadService","文件开始下载... url="+url); //模拟下载文件操作
Thread.sleep(3000); Log.e("DownloadService","文件下载完成...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

继承IntentService类,实现onHandleIntent(Intent intent)方法

注意,不要忘了DownloadService需要在清单文件中注册

2 我们在界面上的按钮的点击事件中,来下载一个文件,如下

  findViewById(R.id.tv_hello).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("DownloadService","当前线程名:"+Thread.currentThread().getName()); //像平时启动service方式一样,没有任何区别
Intent intent = new Intent(MainActivity.this,DownloadService.class);
intent.putExtra("url","http://xx/test.apk");
startService(intent);
}
});

点击按钮,输出

E/DownloadService: 当前线程名:main

E/DownloadService: 当前线程名:IntentService[DownloadService]

E/DownloadService: 文件开始下载... url=http://xx/test.apk

E/DownloadService: 文件下载完成...

通过输出日志,可以看到,开启任务是在主线程中,而执行下载文件的耗时任务,是在子线程中,使用的时候,只需要startService(Intent intent),并通过intent把所需要的数据带过去就行了。是不是很简单。

下面来分析IntentService是如何做到的?

三 IntentService源码分析

1 看下IntentService的类定义

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);
}
} ......
}

可以看到,IntentService有几个需要注意的地

  1. IntentService是一个Service也是一个抽象类,子类只需要实现void onHandleIntent(@Nullable Intent intent)并在里面添加自己的业务即可

  2. IntentService类中有一个 Looper mServiceLooper以及一个ServiceHandler mServiceHandler,

  3. ServiceHandler继承Handler,并在handleMessage()中调用了外部类的onHandleIntent方法

  4. ServiceHandlerhandleMessage()方法中,执行完onHandleIntent((Intent)msg.obj),调用了stopSelf(msg.arg1)来关闭这个Service

所以IntentService不用去管怎么创建的,怎么关闭的,怎么开启线程的,我们只需要继承IntentService,实现onHandleIntent()方法并在里面执行我们的逻辑就行了,执行完任务之后,自动会把Service关闭。这一切都是IntentService帮我们封装好了的。

2 startService之后,会走Service的生命周期方法,onCreate()源码如下

   @Override
public void onCreate() {
super.onCreate(); //还记得上一篇讲的HandlerThread源码分析吗
//创建一个HandlerThread对象,并调用start()方法
//使之成为一个looper线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start(); //拿到上面创建的looper线程对应的looper
//并传给ServiceHandler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

很明显,在onCreate中创建了一个线程而且是一个looper线程,又创建了一个Handler对象,并把这个线程的looper传给了这个Handler,那么这个Handler发送的任务消息都会由这个ServiceHandler处理了

再看看 onStart()方法和onStartCommand()方法,如下

onStart()方法

    @Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}

onStartCommand()方法

  @Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

startService方法启动的时候,第一次会调用onCreate() -> onStart() -> onStartCommand()方法

而且之后再次调用startService方法启动的时候,不会再调用onCreate()方法了,而是会调用onStandCommand()方法

而在IntentService中,onStartCommand()方法中又会调用onStart()方法,所以,我们只需要分析onStart()方法即可

onStart()方法源码

   @Override
public void onStart(@Nullable Intent intent, int startId){
//使用mServiceHandler获取一个消息
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent; //发送这个消息
mServiceHandler.sendMessage(msg);
}

通过上面可知,我们调用startService方法启动service的时候,会调用onStart()方法,在这个方法里面,把intent和startId赋值给了 msg ,并发送消息。这时候会调用Handler的handleMessag()方法,ServiceHandler的源码如下:

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);
}
} ......
}

可以看到ServiceHandler是IntentService的内部类,而且在handleMessage中会调用IntentService的 onHandleIntent()方法,并把 intent 参数也传过去。

我们来看下 onHandleIntent()方法

protected abstract void onHandleIntent(@Nullable Intent intent);

是一个抽象方法,这时候就需要子类去实现这个方法并在里面做耗时的操作即可。

经过上面的分析可知,IntentService使用也非常方便,原理就是利用HandlerThread开启了一个looper线程,并在onStart中把intent通过msg发送出去,并在handleMessage中又调用了onHandleIntent方法,子类实现即可

IntentService使用以及源码分析的更多相关文章

  1. Android源码分析-消息队列和Looper

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17361775 前言 上周对Android中的事件派发机制进行了分析,这次博主 ...

  2. Android HandlerThread 源码分析

    HandlerThread 简介: 我们知道Thread线程是一次性消费品,当Thread线程执行完一个耗时的任务之后,线程就会被自动销毁了.如果此时我又有一 个耗时任务需要执行,我们不得不重新创建线 ...

  3. Android IntentService的使用和源码分析

    引言 Service服务是Android四大组件之一,在Android中有着举足重轻的作用.Service服务是工作的UI线程中,当你的应用需要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界 ...

  4. Android异步消息传递机制源码分析

    1.Android异步消息传递机制有以下两个方式:(异步消息传递来解决线程通信问题) handler 和 AsyncTask 2.handler官方解释的用途: 1).定时任务:通过handler.p ...

  5. Android 进阶16:IntentService 使用及源码解析

    It's time to start living the life you've only imagined. 读完本文你将了解: IntentService 简介 IntentService 源码 ...

  6. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  7. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  8. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  9. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

随机推荐

  1. window7_64安装STAF

    1.       安装包下载 从http://sourceforge.net/projects/staf/files/staf/V3.4.17/下载所需安装包,有Windows.Linux.Solar ...

  2. HDU 2845 Beans (两次线性dp)

    Beans Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  3. Eclipse中Easy Shell插件配置PowerCmd

    1.了解EasyShell.PowerCMD和基本命令 http://sourceforge.net/projects/pluginbox/ http://www.powercmd.com/ 了解基本 ...

  4. 使用Poi对EXCLE的导入导出

    import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import ...

  5. shell学习五十六天----延迟进程调度

    延迟进程调度 前言:大部分时候,我们都希望进程快点開始,开点结束,别卡.而shell的运行,也是在前一个命令后,立即接着运行下一个命令.命令完毕的速度是与资源的限制有关,且不在shell的权限下. 在 ...

  6. Session 钝化机制

  7. 用redis实现动态时间段内统计排序

    问题描述 需要根据某类数据在动态时间段内的统计值对这些数据进行排名.例如按过去24小时内点赞数排名的帖子,每隔一小时计算一次结果.以下描述均针对这个例子展开. 解决思路 针对这种问题,我的第一反应是直 ...

  8. 树的深度优先遍历和广度优先遍历的原理和java实现代码

    import java.util.ArrayDeque; public class BinaryTree { static class TreeNode{ int value; TreeNode le ...

  9. js 中call,apply,bind的区别

    call.apply.bind方法的共同点与区别: apply.call.bind 三者都是用来改变函数的this对象的指向: apply.call.bind 三者都可以利用后续参数传参: bind ...

  10. SDUT OJ 1221 亲和数 (找出某个数n所有的因子数,只需要暴力:2->sqrt(n) 即可 )

    亲和数 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 如果a的因子和等于b,b的因子和等于a,且a≠b,则称a,b为亲和数对. ...