一、IntentService 简介
IntentService 是 Service 的子类,比普通的 Service 增加了额外的功能。先看 Service 本身存在两个问题:
Service 不会专门启动一条单独的进程,Service 与它所在应用位于同一个进程中;
Service 也不是专门一条新线程,因此不应该在 Service 中直接处理耗时的任务;
二、IntentService 特征
会创建独立的 worker 线程来处理所有的 Intent 请求;
会创建独立的 worker 线程来处理 onHandleIntent()方法实现的代码,无需处理多线程问题;
所有请求处理完成后,IntentService 会自动停止,无需调用 stopSelf()方法停止 Service;
为 Service 的 onBind()提供默认实现,返回 null;
为 Service 的 onStartCommand 提供默认实现,将请求 Intent 添加到队列中;
三、intentService的工作原理
使用方式步骤
① 定义IntentService的子类:传入线程名称、复写onHandleIntent()方法
② 在Manifest.xml中注册服务
③ 在Activity中开启Service服务
/**
* IntentService是一种特殊的Service,它继承于Service并且还是个抽象类
* 所以我们必须创建它的子类才能使用IntentService
* IntentService可以用来执行后台任务,当任务执行完后就会“自杀”
* 因为它自己也是个服务,所以优先级高于普通的线程,不容易被系统所干掉
* 所以IntentService比较适合执行优先级较高的后台任务
*/
public abstract class IntentService extends Service {
//HandlerThread的looper
private volatile Looper mServiceLooper;
//通过looper创建的一个Handler对象,用于处理消息
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
/**
* 通过HandlerThread线程中的looper对象构造的一个Handler对象
* 可以看到这个handler中主要就是处理消息
* 并且将我们的onHandlerIntent方法回调出去
* 然后停止任务,销毁自己
*/
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
/**
* 收到消息后,会将Intent对象传递给onHandlerIntent方法去处理
* 注意这个Intent对象的内容和外界Activity中startService(intent)
* 中的intent的内容是完全一致的
* 通过这个intent对象可以得到外界启动IntentService时所传递的参数
* 通过这些参数我们就可以区分不同的业务逻辑
* 这样onHandlerIntent就可以对不同的逻辑做出不同的操作了
* 当onHandlerIntent方法执行结束后,IntentService会通过
* stopSelf(int startId)方法尝试停止服务
* 之所以使用stopSelf(int startId)而不是stopSelf()来停止
* 是因为stopSelf()会马上停止服务,但是有可能还有消息未处理
* stopSelf(int startId)则会等所有的消息都处理完后才销毁自己
* 一般来说的话,stopSelf(int startId)在停止之前会判断
* 最近启动服务的次数和startId是不是相等的,如果相等就立刻停止
* 如果不相等说明还有别的消息没处理,就不停止服务
* 具体的要看AMS中的stopServiceToken方法的实现
*/
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
* 构造函数,可以传递一个name参数
*/
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
/**
* 当我们的IntentService第一次启动的时候,onCreate方法会执行一次
* 可以看到方法里创建了一个HandlerThread
* HandlerThread继承Thread,它是一种可以使用Handler的Thread
* 它的run方法里通过Looper.prepare()来创建消息队列
* 并通过Looper.loop()来开启消息循环,所以就可以在其中创建Handler了
* 这里我们通过HandlerThread得到一个looper对象
* 并且使用它的looper对象来构造一个Handler对象,就是我们上面看到的那个
* 这样做的好处就是通过mServiceHandler发出的消息都是在HandlerThread中执行
* 所以从这个角度来看,IntentService是可以执行后台任务的
*/
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
* 这个方法里的实现其实就很简单了,就是通过handler发送了一个消息
* 把我们的intent对象和startId发送出去
* 在我们上面的handleMessage()会接收到消息
* 并且通过onHandlerIntent()方法将对象回调给子类
*/
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* 每次启动IntentService,onStartCommand()就会被调用一次
* 在这个方法里处理每个后台任务的intent
* 可以看到在这个方法里调用的是上方的onStart()方法
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
/**
* 因为looper是无限循环轮询消息的一个机制,所以当我们明确不需要继续使用的话
* 那么我们就应该通过它的quit()方法来终止它的执行
* 这是个编程的好习惯,要记住哦!
*/
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* 这个方法的注释写了:除非你为这个service提供了绑定,否则不需要实现这个方法
* 因为这个方法默认是返回null的
* 所以咱们不用太关注这个方法
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* 这就是IntentService中定义的抽象方法
* 具体交由它自己的子类来实现
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
四、区别
IntentService 与 Service的区别:(service(不是单独进程和应用程序同进程)intentService(是一个处理异步请求类,专处理耗时任务))
Service 是长期运行在后台的应用程序组件 。
Service 不是一个单独的进程,它和应用程序在同一个进程中,
Service 也不是一个线程,它和线程没有任何关系,所以它不能直接处理耗时操作。
如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR .如果有耗时操作就必须开启一个单独的线程来处理
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,
启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后, IntentService 会自动停止 ,而不需要我们去手动控制。
另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,
并且,每次只会执行一个工作线程,执行完第一个再执行第二个, 有序执行
IntentService :使用场景——
(分析源码得下面)
IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,
启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。
另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
IntentService与Service的不同:
(1)直接 创建一个默认的工作线程,该线程执行所有的intent传递给onStartCommand()区别于应用程序的主线程。
(2)直接创建一个工作队列,将一个意图传递给你onHandleIntent()的实现,所以我们就永远不必担心多线程。
(3)当请求完成后自己会调用stopSelf(),所以你就不用调用该方法了。
(4)提供的默认实现onBind()返回null,所以也不需要重写这个方法。so easy啊
(5)提供了一个默认实现onStartCommand(),将意图工作队列,然后发送到你onHandleIntent()实现。真是太方便了
我们需要做的就是实现onHandlerIntent()方法,还有一点就是经常被遗忘的,构造函数是必需的。
简单说呢?第一,我们省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service
Thread和Service的区别
Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。
那么为什么我们不直接用Thread而要用Service呢?其实这跟 android 的系统机制有关,我们先拿Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
Thread和Service的使用场景:
1、在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务。同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,需要长时间运行的情况下使用线程。
2、如果任务占用CPU时间多,资源大的情况下,要使用线程。
Android 中的异步消息处理主要由四个部分组成,Message、Handler、MessageQueue 和Looper。其中Message 和Handler 我们已经接触过了,而MessageQueue 和Looper对于你来说还是全新的概念,下面我就对这四个部分进行一下简要的介绍。
1. Message
Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。上一小节中我们使用到了Message 的what 字段,除此之外还可以使用arg1 和arg2 字段来携带一些整型数据,使用obj 字段携带一个Object 对象。
2. Handler
Handler 顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用Handler 的sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中。
3. MessageQueue
MessageQueue 是消息队列的意思,它主要用于存放所有通过Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
4. Looper
Looper 是每个线程中的MessageQueue 的管家,调用Looper 的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue 中存在一条消息,就会将它取出,并传递到Handler 的handleMessage()方法中。每个线程中也只会有一个Looper 对象。
第一种:使用handler
缺点明显:
使用handler进行异步处理时,容易产生内存泄漏问题。固然可以通过将handler设置为静态内部类,解决这个问题,但是将handler设置为静态内部类后就无法引用内部成员变量。
内存泄漏原因:
Activity要销毁时,消息队列里消息没处理完,Message Queue默认引用handler,handler默认引用activity。
第二种:使用IntentService(异步任务处理服务)
优点:可以在后台执行,不受Activity生命周期影响。(只能通过startActivity()启动IntentService,可以像普通service一样绑定activity,通过Binder通信)
缺点:如果说消息队列里没消息了,那么service会暂停,内存不够的情况下有可能被系统杀死。
第三种:使用handlerThread(一个继承了Thread的handler处理类)
Thread + 消息机制
优点:使用非常灵活(自己手写的代码一般也是最多的)一般只在Activity里使用,主线程,工作线程均可实现自己的handler机制。
缺点:Activity挂了,也就跟着挂了,需要后台运行那就用IntentService。
第四种:使用AsyncTask
优点:被封装过,需要显示进度条的情况下非常方便,可以串行,也可以并行。
缺点:没那么灵活,只能在主线程里创建。