Android——intentservice介绍

一、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

优点:被封装过,需要显示进度条的情况下非常方便,可以串行,也可以并行。

缺点:没那么灵活,只能在主线程里创建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙小小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值