【转载】Android IntentService使用全面介绍及源码解析
一 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的特点:
- IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue的形式;
- 由于是单线程(一个工作线程),所以所有的任务需要排队执行;/
- 避免了我们再去创建线程和管理service的结束工作;
基于以上,IntentService与Service比较的好处有:
- 第一,使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
- 第二,当操作完成时,我们不用手动停止Service。
当然,IntentService的缺点也是显而易见:
由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况;
二 DEMO实践
DEMO场景描述:
主要由MainActivity和MyIntentService构成,在MainActivity中启动服务,并传递两个参数a和b,在MyIntentService中获取参数,求和,并通过发送广播的形式向UI返回结果,然后MainActivity在接收到广播之后更新UI。
MainActivity.java主要做了三件事:
- 注册/注销广播接收器;
- 创建UI和更新UI;
- 传递参数,启动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中可以看出:
- UI线程的线程ID=30060,而onHandleIntent()的线程ID分别是30223,30305;由此知道onHandleIntent()方法是执行在工作线程中的;
- 并且IntentService的所有请求如果是在一个生命周期中完成的话,则所有请求是在一个工作线程中顺序执行的。否则,是在不同的工作线程中完成。
- 同时验证了:执行完所一个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使用全面介绍及源码解析的更多相关文章
- Android IntentService使用介绍以及源码解析
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- Android进阶:五、RxJava2源码解析 2
上一篇文章Android进阶:四.RxJava2 源码解析 1里我们讲到Rxjava2 从创建一个事件到事件被观察的过程原理,这篇文章我们讲Rxjava2中链式调用的原理.本文不讲用法,仍然需要读者熟 ...
- IPerf——网络测试工具介绍与源码解析(4)
上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直 ...
- 【Android编程】android平台的MITM瑞士军刀_cSploit源码解析及中间人攻击复现
/文章作者:Kali_MG1937 作者博客ID:ALDYS4 QQ:3496925334 未经允许,禁止转载/ 何为MITM欺骗,顾名思义,中间人攻击的含义即为在局域网中充当数据包交换中间人的角色 ...
- Android开发——AsyncTask的使用以及源码解析
.AsyncTask使用介绍 转载请标明出处:http://blog.csdn.net/seu_calvin/article/details/52172248 AsyncTask封装了Thread和 ...
- IPerf——网络测试工具介绍与源码解析(1)
IPerf是一个开源的测试网络宽带并能统计并报告延迟抖动.数据包丢失率信息的控制台命令程序,通过参数选项可以方便地看出,通过设置不同的选项值对网络带宽的影响,对于学习网络编程还是有一定的借鉴意义,至少 ...
随机推荐
- Apache—伪静态配置和使用
https://jingyan.baidu.com/article/ae97a646a7419bbbfd461df7.html https://blog.csdn.net/weixin_4178205 ...
- gdisk转fdisk
分区测试的时候发现之前用gdisk分区之后,就无法用fdisk进行分区了,哪怕格式化了也不行,通过fdisk 查看硬盘,发现硬盘都变成了GPT分区,无法通过fdisk进行分区操作,所以要通过parte ...
- (办公)记事本_Linux帮助命令
参考:http://www.gulixueyuan.com/course/300/task/7086/show# 帮助命令: .man命令 1.1.man命令是Linux下的帮助指令,通过man指令可 ...
- Python活力练习Day3
Day3:请输入星期几的第一个字母来判断是星期几,如果第一个字母一样,则继续判断第二个字母. #这是一道典型的题,一次输入一个字母,首字母匹配一个list里的内容.如果匹配到多个,再输入并匹配第二个字 ...
- C语言搬书学习第一记 —— 认识一个简单程序的细节
#include<stdio.h> /*告诉编译器把stdio.h 中的内容包含在当前程序中,stdio.h是C编译器软件包的标准部分,它提供键盘输入和 屏幕输入的支持studio.h文件 ...
- 使用EasyPOI导入导出图片出现数组越界异常
在我使用easypoi做导出功能的时候,突然抛了一个数组越界异常,找了很久也没找到,最后猜想有可能是路径出了问题,然后打印了一下图片存放的路径,结果发现在其保存路径上存在“.”,也就是easypoi底 ...
- Axure制作dialog效果的动作步骤
1.在Axure中添加一个弹框按钮 2.将动态面版拖动到界面中 3.双击动态面版,双击state 4.拖入一块图片占位符进来 5.设置图片 6.回到上一个界面设置动态面版的大小,使其 ...
- ES6-WeakSet数组结构
WeakSet 也会去重 总结: 1.成员都是对象: 2.成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏: 3.不能遍历,方法有 add.delete.has. ...
- (草稿)如何判断一名UiPath开发人员是否合格?
一名合格的UiPath开发人员究竟需要具备什么核心技能?业务梳理?沟通技巧?VB.net吗?VBA吗?Python?还是SQL?出于多种原因,关于这一点总是众说纷纭,莫衷一是.尽管这些技术都算沾边,但 ...
- Mysql增量备份之Mysqldump&Mylvmbackup
简单介绍 备份类型 备份方式 热备份:备份期间不需要服务停机,业务不受影响: 温备份:备份期间仅允许读的请求: 冷备份:备份期间需要关闭Mysql服务或读写请求都不受影响: 完全备份:full bac ...