一 IntentService介绍

IntentService定义的三个基本点:是什么?怎么用?如何work?

官方解释如下:

//IntentService定义的三个基本点:是什么?怎么用?如何work?*/

1、IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand.

2、Clients send requests through startService(Intent) calls;

3、the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

//解释了IntentService的好处,以及How to use IntentService*/

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 onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

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.

总结IntentService的特点如下:

1、IntentService是Service类的子类,用来处理异步请求。

2、客户端可以通过startService(Intent)方法传递请求给IntentService

3、IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)所对应的任务,这样以免事务处理阻塞主线程。

4、执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。

5、IntentService在处理事务时,还是采用的Handler方式,创建一个名叫ServiceHandler的内部Handler,并把它直接绑定到HandlerThread所对应的子线程。 ServiceHandler把处理一个intent所对应的事务都封装到叫做onHandleIntent的虚函数;因此我们直接实现虚函数onHandleIntent,再在里面根据Intent的不同进行不同的事务处理就可以了。

IntentService最重要的一个方法onHandleIntent:

This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().

1、该函数用于针对Intent的不同进行不同的事务处理.执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,
则自动停止Service;否则ServiceHandler会取得下一个Intent请求传人该函数来处理其所对应的任务。

2、所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),但是同一时间只处理一个请求。

IntentService的特点、优点、缺点?

IntentService的特点:

  1. IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue的形式;
  2. 由于是单线程(一个工作线程),所以所有的任务需要排队执行;/
  3. 避免了我们再去创建线程和管理service的结束工作;

基于以上,IntentService与Service比较的好处有:

  • 第一,使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
  • 第二,当操作完成时,我们不用手动停止Service。

当然,IntentService的缺点也是显而易见:

由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况;

二 DEMO实践

DEMO场景描述:

主要由MainActivity和MyIntentService构成,在MainActivity中启动服务,并传递两个参数a和b,在MyIntentService中获取参数,求和,并通过发送广播的形式向UI返回结果,然后MainActivity在接收到广播之后更新UI。

MainActivity.java主要做了三件事:

  1. 注册/注销广播接收器;
  2. 创建UI和更新UI;
  3. 传递参数,启动MyIntentService;

代码如下:

public class MainActivity extends AppCompatActivity {

    private LinearLayout ll_container;
private BroadcastReceiver forSumReceiver=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("TAG","onReceive ()");
if(intent.getAction()==Constans.ACTION_RESULT){
int a=intent.getIntExtra(Constans.A,0);
int result=intent.getIntExtra(Constans.RESULT,0);
Log.i("TAG","onReceive --result:"+result);
handleResult(a,result);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ll_container= (LinearLayout)findViewById(R.id.ll_container);
Log.i("TEST","MainActivity:"+android.os.Process.myTid());
registerBroadcast();
} private void handleResult(int a,int result){
TextView textView=(TextView)ll_container.findViewWithTag(a);
String old=textView.getText().toString();
String newText=old.replaceAll(" 正在计算中...",String.valueOf(result)+" 计算Success");
textView.setText(newText);
} private void registerBroadcast(){
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction(Constans.ACTION_RESULT);
registerReceiver(forSumReceiver,intentFilter);
} private int a=1;
public void addTask(View view){
int b=new Random().nextInt(101)+1;
MyIntentService.startMyIntentService(this,a,b);
TextView textView=new TextView(this);
textView.setText(a+"+"+b+"= "+ " 正在计算中...");
textView.setTag(a);
ll_container.addView(textView);
a++;
} @Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(forSumReceiver);
}
}

MyIntentService用于接收参数,并返回计算的结果:

public class MyIntentService extends IntentService {

    public MyIntentService() {
//必须实现父类的构造方法
super("MyIntentService");
} @Override
public void onCreate() {
Log.i("TEST","onCreate()");
super.onCreate();
} @Override
public void onStart(Intent intent, int startId) {
Log.i("TEST","onStart()");
super.onStart(intent, startId);
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("TEST","onStartCommand()");
return super.onStartCommand(intent, flags, startId);
} @Override
public IBinder onBind(Intent intent) {
Log.i("TEST", "onBind()");
return super.onBind(intent);
} @Override
public void onDestroy() {
Log.i("TEST","onDestroy()");
super.onDestroy();
} @Override
protected void onHandleIntent(Intent intent) {
Log.i("TEST","onHandleIntent():"+android.os.Process.myTid());
if (intent!=null){
String action=intent.getAction();
if(Constans.ACTION_FOR_SUM.equals(action)){
int a=intent.getIntExtra(Constans.A,0);
int b=intent.getIntExtra(Constans.B,0);
int result=a+b;
Log.i("TEST","result: "+result);
handleResult(a,result);
}
}
} private void handleResult(int a,int result){
try{
//模拟计算耗时
Thread.sleep(3000);
Intent intent=new Intent(Constans.ACTION_RESULT);
intent.putExtra(Constans.RESULT,result);
intent.putExtra(Constans.A,a);
sendBroadcast(intent);
}catch (InterruptedException e){
e.printStackTrace();;
}
} public static void startMyIntentService(Context context,int a,int b){
Intent intent=new Intent(context,MyIntentService.class);
intent.setAction(Constans.ACTION_FOR_SUM);
intent.putExtra(Constans.A,a);
intent.putExtra(Constans.B,b);
context.startService(intent);
} }

IntentService生命周期方法执行顺序如下:

07-08 10:18:51.579 com.troy.intentservicedemo I/TEST: MainActivity:30060
07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onCreate()
07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onStartCommand()
07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onStart()
07-08 10:19:26.039 com.troy.intentservicedemo I/TEST: onHandleIntent():30223
07-08 10:19:26.039 com.troy.intentservicedemo I/TEST: result: 23
07-08 10:19:29.100 com.troy.intentservicedemo I/TEST: onDestroy()
07-08 10:19:31.839 com.troy.intentservicedemo I/TEST: onCreate()
07-08 10:19:31.849 com.troy.intentservicedemo I/TEST: onStartCommand()
07-08 10:19:31.849 com.troy.intentservicedemo I/TEST: onStart()
07-08 10:19:31.869 com.troy.intentservicedemo I/TEST: onHandleIntent():30305
07-08 10:19:31.869 com.troy.intentservicedemo I/TEST: result: 52
07-08 10:19:34.899 com.troy.intentservicedemo I/TEST: onDestroy()

从上面Log中可以看出:

  1. UI线程的线程ID=30060,而onHandleIntent()的线程ID分别是30223,30305;由此知道onHandleIntent()方法是执行在工作线程中的;
  2. 并且IntentService的所有请求如果是在一个生命周期中完成的话,则所有请求是在一个工作线程中顺序执行的。否则,是在不同的工作线程中完成。
  3. 同时验证了:执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;

运行效果如图:

三 IntentService源码简单解析

IntentService是Service的子类,拥有Service的所有生命周期方法;同时还有自己的ServiceHandler;

ServiceHandler相关源码如下:

public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;//volatile关键字保证同步,保证可见性
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);
}
} public IntentService(String name) {//构造方法
super();
mName = name;
}

IntentService 实际上是Looper,Handler,Service 的集合体,他不仅有服务的功能,还有处理和循环消息的功能。

onCreate()的源码:创建了一个HandlerThread

@Override
public void onCreate() {
super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start(); mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

IntentService创建时就会创建Handler线程(HandlerThread)并且启动,然后再得到当前线程的Looper对象来初始化IntentService的mServiceLooper,接着创建mServicehandler对象。

下面是onStart()的源码: 调用mServiceHandler

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

当你启动IntentService的时候,就会产生一条附带startId和Intent的 Message并发送到MessageQueue中,接下来Looper发现MessageQueue中有Message的时候,就会停止Handler 处理消息。

handleMessage处理的代码如下:

@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}

接着调用 onHandleIntent((Intent)msg.obj),这是一个抽象的方法,其实就是我们要重写实现的方法,我们可以在这个方法里面处理我们的工作.当任务完成时就会调用stopSelf(msg.arg1)这个方法来结束指定的工作。

stopSelf(msg.arg1):

注意下:回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.如果传入的是-1则直接销毁。

当所有的工作执行完后:就会执行onDestroy方法。

onDestroy源码如下:

@Override
public void onDestroy() {
mServiceLooper.quit();
}

服务结束后调用这个方法 mServiceLooper.quit()使looper停下来。

最后总结一下上述的分析:

1、 IntentService是一个基于消息的服务,每次启动该服务并不是马上处理你的工作,而是首先会创建对应的Looper,Handler并且在MessageQueue中添 加的附带客户Intent的Message对象, 当Looper发现有Message的时候接着得到Intent对象通过在 onHandleIntent((Intent)msg.obj)中调用你的处理程序. 处理完后即会停止自己的服务. 意思是Intent的生命周期跟你的 处理的任务是一致的. 所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出。

2、IntentService是不适合用于bindService()这样的启动方式的。其次我们通过startService多次启动Service时,相当于在MessageQueue中添加了多个任务,就可以实现多任务按照顺序执行。

3、只有在onHandleIntent()方法中执行的代码才是在工作线程中运行的。IntentService的停止不是因为在handleMessage() 中执行了stopSelf(msg.arg1);而是系统自己停止的。

【转载】Android IntentService使用全面介绍及源码解析的更多相关文章

  1. Android IntentService使用介绍以及源码解析

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...

  2. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  3. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  5. Android进阶:五、RxJava2源码解析 2

    上一篇文章Android进阶:四.RxJava2 源码解析 1里我们讲到Rxjava2 从创建一个事件到事件被观察的过程原理,这篇文章我们讲Rxjava2中链式调用的原理.本文不讲用法,仍然需要读者熟 ...

  6. IPerf——网络测试工具介绍与源码解析(4)

    上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直 ...

  7. 【Android编程】android平台的MITM瑞士军刀_cSploit源码解析及中间人攻击复现

    /文章作者:Kali_MG1937 作者博客ID:ALDYS4 QQ:3496925334 未经允许,禁止转载/ 何为MITM欺骗,顾名思义,中间人攻击的含义即为在局域网中充当数据包交换中间人的角色 ...

  8. Android开发——AsyncTask的使用以及源码解析

    .AsyncTask使用介绍  转载请标明出处:http://blog.csdn.net/seu_calvin/article/details/52172248 AsyncTask封装了Thread和 ...

  9. IPerf——网络测试工具介绍与源码解析(1)

    IPerf是一个开源的测试网络宽带并能统计并报告延迟抖动.数据包丢失率信息的控制台命令程序,通过参数选项可以方便地看出,通过设置不同的选项值对网络带宽的影响,对于学习网络编程还是有一定的借鉴意义,至少 ...

随机推荐

  1. CDN原理加速解析

    CDN概念 CDN全称叫做“Content Delivery Network”,中文叫内容分发网络.   原理分析 我们知道,当我们使用域名访问某一个网站时,实际上就是将请求包(以Http请求为例)通 ...

  2. Mac 停止redis服务

    停止redis服务: redis-cli shutdown 开始redis服务: redis-server

  3. [20191218]降序索引疑问4.txt

    [20191218]降序索引疑问4.txt --//前几天优化一个项目,我发现许多表里面有有隐含字段,一般开发很少建立函数索引.我自己检查发现里面存在大量的降序索引.--//我感觉有点奇怪,为什么开发 ...

  4. 如何安装 IntelliJ IDEA 最新版本——详细教程

    IntelliJ IDEA 简称 IDEA,被业界公认为最好的 Java 集成开发工具,尤其在智能代码助手.代码自动提示.代码重构.代码版本管理(Git.SVN.Maven).单元测试.代码分析等方面 ...

  5. Larave中CSRF攻击

    1.什么是CSRF攻击?            CSRF是跨站请求伪造(Cross-site request forgery)的英文缩写\          Laravel框架中避免CSRF攻击很简单 ...

  6. 微信小程序-强制手机端更新

    小程序的更新机制 开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本.微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会静默更新 ...

  7. How to: Create a Business Model in the XPO Data Model Designer 如何:在 XPO 数据模型设计器中创建业务模型

    This topic provides step-by-step instructions on how to use the XPO Data Model Designer in XAF appli ...

  8. tomcat修改使用指定的jdk版本

    linux安装的jdk1.6,无法满足当前tomcat项目使用,所以需要指定为更高版本的jdk. 主要修改tomcat bin目录下的catalina.sh和setclasspath.sh文件 添加内 ...

  9. 验证apk签名方式(V1 || V2)

    进入SDK\build-tools\28.0.2目录(或者其他版本),该目录有apksigner.bar脚本,我们可以利用它来验证. 在此目录打开命令行. 命令为:apksigner verify - ...

  10. BIM工程信息管理系统-EF实体框架数据操作基类

    EF实体框架数据操作基类主要是规范增.改.查.分页.Lambda表达式条件处理,以及异步操作等特性,这样能够尽可能的符合基类这个特殊类的定义,实现功能接口的最大化重用和统一. 1.程序代码 /// & ...