IntentService使用以及源码分析

九路 等级 611 0 0

一 概述

我们知道,在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)并在里面添加自己的业务即可
  1. IntentService类中有一个 Looper mServiceLooper以及一个ServiceHandler mServiceHandler,

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

  3. 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使用以及源码分析
一 概述 我们知道,在Android开发中,遇到耗时的任务操作时,都是放到子线程去做,或者放到Service中去做,在Service中开一个子线程来执行耗时操作。 那么,在Service里面我们需要自己管理Service的生命周期,何时开启何时关闭,还是很麻烦的,还好Android给我们提供了一个这样的类,叫做IntentService 那么Intent
Android Service学习之IntentService 深入分析
官方的解释是: IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through android.content.Context.star
android Activity之间的参数传递
在开发web程序的时候,我们都知道web页面之间是可以传递参数的,在android中,每一个activity就相当于一个页面(窗口), 当然,它也是可以传递参数的。 思路:通过Intent --->激活组件(Activity),附带数据 Intent(意向): 一:通过Intent对象可以激活组件activity,具体有五种方式: 方式1:
Android HandlerThread和IntentService
HandlerThread HandlerThread继承了Thread,它是一种可以使用Handler的Thread,它实现也很简单,就是在run中通过Looper.prepare()来创建消息队列,并且通过Looper.loop()来开启消息循环,这样再实际使用中就允许在HandlerThread中创建Handle了。 public cla
Android Service的onStartCommand返回值用法
Android Service的onStartCommand返回值用法 ### 本文目的:使读者快速理解 1、START\_STICKY: 如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由 于服务状态为开始状态,所以创建服务后一定会调用onStartComma
Android 通过Intent调用系统功能和Action动作和服务广播【大全】
### **1.从google搜索内容** Intent intent = new Intent(); intent.setAction(Intent.ACTION\_WEB\_SEARCH); intent.putExtra(SearchManager.QUERY,”searchString”) startActivity(intent);
Android实现分享功能
最近是越来越懒了,连打字都懒着打,最近有人问到Android分享功能用那个比较好,使用Android自带的Intent来进行分享还是借助第三方呢,直接上代码: 一:使用Intent直接和第三方应用进行通信: /\*\* \* 分享功能 \* \* @param context \*
EventBus使用详解
[EventBus](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Flink.jianshu.com%3Ft%3Dhttps%3A%2F%2Fgithub.com%2Fgreenrobot%2FEventBus)是针一款对Android的发布/订阅事件总线。它可以让我们很轻松的实现在And
EventBus学习
1. 基本的:http://www.360doc.com/content/14/0821/16/19022950\_403599285.shtml 2. 详细的:http://www.cnblogs.com/angeldevil/p/3715934.html 前几天,有个朋友遇到一个面试题,问在一个 android applic
IntentService用法小结
废话少说,先总结: 1\. Service 默认是在主线程(UI线程)运行的。 2\. IntentService可以为我们开启一个独立的线程来工作。 注:IntentService必须开启一个无参的构造方法。 流程:构造方法--->onCreate---->onStartCommand--->onHandlerIntent--->onDestory
IntentService的特点
**IntentService的特点** IntentService具有以下特点: * 1\. IntentService自带一个工作线程,当我们的Service需要做一些可能会阻塞主线程的工作的时候可以考虑使用IntentService。 * 2\. 我们需要将要做的实际工作放入到IntentService的onHandleIntent回到方法
IntentService类 和 异步任务(AsyncTask)
IntentService是一个Service类。 IntentService只有1个带String参数的构造方法,所以,在自定义类继承IntentService时,需要在自定义类中显式的调用IntentService带参数的构造方法,并且将自定义类的构造方法修改为无参数的。 IntentService内部使用消息机制,利用消息队列的特性,可以依次处
Intent传递对象的几种方式
**Intent的用法相信你已经比较熟悉了,Intent可以用来启动Activity,Service等等,同时我们也可以通过Intent来进行传递数据,比如以下代码**    Intent intent=new Intent(MainActivity.this,OtherActivity.class);                 in
Rxjava和EventBus对比
总的来说,EventBus是一款针对Android优化的发布/订阅事件总线,主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息。而Rxjava则是一种基于异步数据流的处理方案。如果一个订阅者需要注册多个事件的时候,Rxjava需要一个个单独的注册,而EventBus则可以实现一