四大组件——Service

229 阅读15分钟

一、简介

service也是Android四大组件之一,它的主要作用就是在后台运行,可以跨进程通信,并且没有提供用户界面的。service可以长期一直在后台运行,除非系统资源紧张被回收,否则不会被停止或者销毁。使用service有2种方式:startServicebindServicestartService方式可以和service进行简单的通信,而bindService可以用来进行IPC通信。

另外需要区别于thread线程,thread是在一个单独的线程中执行,而service是运行在主线程中的,其中不能进行很耗时的操作,否则就会导致ANR,如果要进行耗时操作,还是需要使用thread来创建一个线程,所以它们两个没有什么关系。如果需要长时间的在后台运行,比如播放音乐等不需要控制UI也不耗时的话,就使用service;如果需要耗时操作,比如访问网络等就需要使用thread。

二、service的生命周期

启动一个service有两种方式::startServicebindService,从上图中我们可以看出,通过这两种不同的方式启动service,他们的生命周期方法会有一些不同。通过startService启动,会回调onStartCommand方法;通过bindService启动,会回调onBind方法。

停止一个service也有两种方式:stopServiceunbindService,但是这两种方式是需要根据启动service的方式来选择的:如果是通过startService方式来启动,就需要调用stopService方法来停止,此时会回调onDestroy方法;如果是通过bindService,需要调用unbindService来解绑,不仅会回调onDestroy方法,而且在onDestroy之前,还会回调onUnbind方法。另外,通过startService启动的service不能通过unbindService来停止,通过bindService启动的service不能通过stopService来停止服务。最后,可以在service的内部通过stopSelf方法来停止服务自身,同样的,调用此方法后,也会回调onDestroy方法,但此方法不会作用于通过bindService启动的服务。

另外,当定义好一个service类之后,需要在manifest中进行注册,不管是通过startService还是bindService启动的服务。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.service.use">
    ...
    <service android:name=".service.ServiceOne" android:label="ServiceOne"/>
    <service android:name=".service.ServiceTwo" android:label="ServiceTwo"/>
    <service android:name=".service.ServiceThree" android:label="ServiceThree"/>
    ...
</manifest>

三、使用

1、启动startService

启动服务

val intent = Intent(this,ServiceOne::class.java)
startService(intent)

停止服务

val intent = Intent(this,ServiceOne::class.java)
stopService(intent)

具体的ServiceOne

class ServiceOne : Service(){

    override fun onCreate() {
        super.onCreate()
        println("ServiceOne-->onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("ServiceOne-->onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder? {
        println("ServiceOne-->onBind")
        return null
    }

    override fun onUnbind(intent: Intent?): Boolean {
        println("ServiceOne-->onUnbind")
        return super.onUnbind(intent)
    }

    override fun onDestroy() {
        println("ServiceOne-->onDestroy")
        super.onDestroy()
    }
}

在Activity中调用startService(Intent)方法,即可启动一个service。

  1. 第一次点击start_service按钮后,我们会看到以下输出:

2. 当再次点击start_service按钮后,可以看到下面的输出:

说明onCreate方法在service生命周期中只会回调一次,而onStartCommand会回调多次。注意,由于onStart方法已经不再推荐使用,推荐使用onStartCommand方法,所以本文中不再说明。onStartCommand方法的返回值必须是Service.START_STICKY_COMPATIBILITYService.START_STICKYService.START_NOT_STICKYService.START_REDELIVER_INTENT这4个中的其中1个,下面分别说明这几个返回值的含义。

返回值 说明
Service.START_STICKY_COMPATIBILITY 它是START_STICKY的兼容版本,不保证服务被kill后一定能重启
Service.START_STICKY 如果Service所在的进程,在执行了onStartCommand方法后被kill了,那么这个Service会被保留在已开始的状态,但是不保留传入的Intent,随后系统会尝试重新创建此Service,由于服务状态保留在已开始状态,所以创建服务后一定会调用onStartCommand方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null,需要我们小心处理。
Service.START_NOT_STICKY 如果Service所在的进程,在执行了onStartCommand方法后被kill了,则系统不会重新启动此Service
Service.START_REDELIVER_INTENT 如果Service所在的进程,在执行了onStartCommand方法后被kill了,则结果和START_STICKY一样,也会重新创建此Service并调用onStartCommand方法。不同之处在于,如果是返回的是START_REDELIVER_INTENT ,则重新创建Service时onStartCommand方法会传入之前的intent
  1. 点击stop_service按钮得到以下输出:

  1. 在service内部调用stopSelf停止自身

ServiceOne类中修改如下代码,在onCreate中倒计时5s后停止服务。

class ServiceOne : Service(){

    private var timer:Timer = Timer()
    private var timerTask:TimerTask? = null
    private var count = 0

    override fun onCreate() {
        super.onCreate()
        println("ServiceOne-->onCreate")
        timerTask = timerTask {
            count++
            println(count)
            if(count > 5){
                println("count超过了5,停止自己")
                stopSelf()
            }
        }
        timer.schedule(timerTask,1000,1000)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("ServiceOne-->onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder? {
        println("ServiceOne-->onBind")
        return null
    }

    override fun onUnbind(intent: Intent?): Boolean {
        println("ServiceOne-->onUnbind")
        return super.onUnbind(intent)
    }

    override fun onDestroy() {
        println("ServiceOne-->onDestroy")
        super.onDestroy()
        timer.cancel()
    }
}

运行程序后,得到以下输出:

  1. 其他

注释掉上面代码中onCreate的if判断,使得可以一直打印计数,当退回到桌面,或者按下返回键销毁Activity后,如果此时app没有被系统完全回收,可以看到后台服务任然会一直打印输出。这就说明以startService方式启动的服务,可以脱离当前Activity,甚至可以"脱离"当前应用,只要系统允许,可以在后台无限运行下去。

在开发者选项中查看正在运行的服务,就可以看到我们的ServiceOne服务还在后台运行着。

2、绑定bindService

绑定服务

var connect = object : ServiceConnection {
    override fun onServiceDisconnected(name: ComponentName?) {
        println("onServiceDisconnected")
    }

    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        println("onServiceConnected")
    }
}
var intentTwo = Intent(this, ServiceTwo::class.java)
bindService(intentTwo, connect, Service.BIND_AUTO_CREATE)

解绑服务

unbindService(connect)

具体的ServiceTwo

class ServiceTwo : Service() {

    var myBinder = MyBinder()

    override fun onCreate() {
        super.onCreate()
        println("ServiceTwo-->onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("ServiceTwo-->onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder? {
        println("ServiceTwo-->onBind")
        return myBinder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        println("ServiceTwo-->onUnbind")
        return super.onUnbind(intent)
    }

    override fun onDestroy() {
        println("ServiceTwo-->onDestroy")
        super.onDestroy()
    }

    class MyBinder : Binder() {
        fun getMessage(msg: String) = println("输入的消息是:$msg")
        fun getAddition(a: Int, b: Int) = println("$a + $b 的值是${a + b}")
        fun getSubtraction(a: Int, b: Int) = println("$a - $b 的值是${a - b}")
    }
}

在Activity中调用bindService(Intent,ServiceConnection,int)方法,即可绑定一个service。

  1. 第一次点击bind_service按钮后,我们会看到以下输出。注意:如果在service 中的onBind方法返回null的话,没有回调onServiceConnected方法。其实这也是正常的,绑定服务就是为了Activity能够和service进行相互通信,如果在onBind返回空,那么绑定服务也没有什么意义。

  2. 当再次点击bind_service按钮后,不会再次回调onCreateonBind方法,说明onCreateonBind方法只会调用一次。

  3. 我们修改上面connect对象中的onServiceConnected方法,使得我们可以调用service中的方法。

private var connect = object : ServiceConnection {
    override fun onServiceDisconnected(name: ComponentName?) {
        println("onServiceDisconnected")
    }

    override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
        println("onServiceConnected")
        binder as ServiceTwo.MyBinder
        binder.getMessage("hello world")
        binder.getAddition(3,2)
        binder.getSubtraction(3,2)
    }
}

运行程序,点击bind_service按钮,会得到以下输出:

可以看到在onServiceConnected方法中有一个IBinder?对象,这个就可以进行Binder通信,只不过Binder不是本文的重点,可以参考其他关于Binder的资料。

  1. 当点击返回按钮,或者销毁当前Activity时,会输出以下信息。可以看出,service是和当前Activity关联的,当Activity被销毁后,service也被解绑并销毁,不会脱离当前Activity单独在后台运行。

  2. 当点击unbind_service按钮后,会输出以下信息。可以看到,只是把service和Activity解绑,服务被销毁。但是并没有回调onServiceDisconnected方法,其实当正常关闭service时,此方法并不会被调用,只有当service由于系统资源不足,被回收或者被异常kill掉,才会回调此方法。

3、启动和绑定

service可以同时被启动并且绑定的,即在调用startService方法启动服务后,也可以继续调用bindService绑定服务,此时就同时拥有了这两种方式的特性:既可以脱离当前Activity在后台独自运行,也可以和Activity进行通信。用ServiceThree类来对这种方式进行测试,代码其实和ServiceTwo大同小异的。需要注意的是,在onUnbind方法里返回了true,这个后面会说明。

class ServiceThree : Service() {

    private var binderThree = BinderThree()

    override fun onCreate() {
        super.onCreate()
        println("ServiceThree-->onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("ServiceThree-->onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder? {
        println("ServiceThree-->onBind")
        return binderThree
    }

    override fun onRebind(intent: Intent?) {
        super.onRebind(intent)
        println("ServiceThree-->onRebind")
    }

    override fun onUnbind(intent: Intent?): Boolean {
        println("ServiceThree-->onUnbind")
        return true
    }

    override fun onDestroy() {
        super.onDestroy()
        println("ServiceThree-->onDestroy")
    }

    class BinderThree : Binder() {
        fun printMessage(msg: String) = println("输出:$msg")
        fun getMultiplication(a: Int, b: Int) = println("$a * $b = ${a * b}")
        fun getDivision(a: Int, b: Int) = println("$a / $b = ${a / b}")
    }
}

SecondActivity中的代码也很简单,定义了两个按钮,一个用于启动并绑定服务,一个用于停止并解绑服务,布局文件就不贴出来了。

class SecondActivity : Activity() {

    private var startAndBindServiceBtn: Button? = null
    private var stopAndUnBindServiceBtn: Button? = null

    private var intentThree: Intent? = null

    private var connectThree = object : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
            println("connectThree-->onServiceDisconnected")
        }

        override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
            println("connectThree-->onServiceConnected")
            binder as ServiceThree.BinderThree
            binder.printMessage("你好,service")
            binder.getMultiplication(6,2)
            binder.getDivision(6,2)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        intentThree = Intent(this, ServiceThree::class.java)

        startAndBindServiceBtn = findViewById(R.id.start_and_bind_service_btn)
        stopAndUnBindServiceBtn = findViewById(R.id.stop_and_unbind_service_btn)
        startAndBindServiceBtn?.setOnClickListener {
            startService(intentThree)
            bindService(intentThree,connectThree, Service.BIND_AUTO_CREATE)
        }
        stopAndUnBindServiceBtn?.setOnClickListener {
            stopService(intentThree)
            unbindService(connectThree)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        println("SecondActivity-->onDestroy")
    }
}
  1. 当我们点击start_and_bind_service按钮后,会得到以下输出。从中我们可以看到,其实就是和上面两种方式的合并。

  2. 当连续点击击start_and_bind_service按钮后,会得到以下输出。还是只会回调onStartCommand,这也说明了onCreateonBindonServiceConnected方法只会调用一次。

  3. 当我们点击stop_and_unbind_service按钮后,会得到以下输出。

  4. 当按下返回按钮回到MainActivity后,会得到以下输出。此时可以看到虽然SecondActivity调用了onDestroy方法,说明已经被销毁,但是并没有调用ServiceThree服务中的onDestroy方法,只是调用了onUnbind方法和当前SecondActivity解绑,这也就说明此时ServiceThree服务并没有被销毁,现在是独立的在后台运行。

    为了验证一下是否还在后台运行,我们修改一下ServiceThree服务onCreate方法中的代码,开启一个Timer使得1s打印一次计数,再次运行程序得到以下输出。从运行结果可以看出,确实是独立在后台运行。

private var myTimer: Timer = Timer()
private var myTimerTask: TimerTask? = null
private var count = 0

override fun onCreate() {
    super.onCreate()
    println("ServiceThree-->onCreate")
    myTimerTask = timerTask {
        count++
        println(count)
    }
    myTimer.schedule(myTimerTask,1000,1000)
}

打开开发者选项中,查看当前运行的服务,可以看到ServiceThree仍然在后台运行,并没有被销毁。

  1. 在第4点中按下返回键调用了onUnbind,就等同于在Activity中调用了unbindService方法,和当前Activity解绑。所以说我们先验证的是调用unbindService,而没有调用stopService方法。经过测试如果只调用stopService方法而不调用unbindService方法,是不会有任何反应的。可以自己写个按钮然后在点击事件中只调用stopService方法试试。

  2. 回到第4点,当我们按下返回键回到MainActivity后,再次点击按钮跳转到SecondActivity,然后点击start_and_bind_service按钮,会得到以下输出。可以看到回调了onStartCommandonServiceConnectedonRebind方法,前两个我们应该知道会被回调的,onStartCommand方法就不多说,解绑了当前Activity,再次绑定肯定会回调onServiceConnected方法,但是为什么不调用onBind,而是调用了onRebind方法。这个就要和之前说过的,在onUnbind方法中返回true的原因,如果返回false或者调用父类的方法return super.onUnbind(intent),再次点击按钮后,不会调用onRebind方法。这个方法我一般用在Notification中,当需要重新绑定服务时,这个方法还是很好用的。

  3. 最后总结一下,当即开启和绑定service后,必须调用stopServiceunbindService方法,才能完全停止一个服务,否则还是会在后台一直运行下去(如果不被系统kill的话)。

四、Android 8.0的限制

从Android 8.0版本开始对service的后台启动做了很大的限制,当应用处于后台时调用startService方法,会抛出java.lang.IllegalStateException异常,当然8.0之前不受影响。

多个 Android 应用和 Service 可以同时运行。 例如,用户可以在一个窗口中玩游戏,同时在另一个窗口中浏览网页,并使用第三个应用播放音乐。 同时运行的应用越多,对系统造成的负担越大。 如果还有应用或 Service 在后台运行,则会对系统造成更大负担,进而可能导致用户体验下降;例如,音乐应用可能会突然关闭。

在后台中运行的 Service 会消耗设备资源,这可能会降低用户体验,对此Google对这些service施加了一些限制。

系统可以区分前台和后台应用。 (用于 Service 限制目的的后台定义与内存管理使用的定义不同;一个应用按照内存管理的定义可能处于后台,但按照能够启动 Service 的定义又处于前台。)如果满足以下任意条件,应用将被视为处于前台:

  • 具有可见 Activity(不管该 Activity 已启动还是已暂停)。

  • 具有前台 Service。

  • 另一个前台应用已关联到该应用(不管是通过绑定到其中一个 Service,还是通过使用其中一个内容提供程序)。 例如,如果另一个应用绑定到该应用的 Service,那么该应用处于前台:

    • IME
    • 壁纸 service
    • 通知侦听器
    • 语音或文本 service

如果以上条件均不满足,应用将被视为处于后台。

请注意:这些应用不会对绑定 Service 产生任何影响。 如果您的应用定义了绑定 Service,则不管应用是否处于前台,其他组件都可以绑定到该 Service。

处于前台时,应用可以自由创建和运行前台与后台service。 进入后台时,在一个持续数分钟的时间窗内,应用仍可以创建和使用 service。 在该时间窗结束后,应用将被视为处于空闲状态。 此时,系统将停止应用的后台 service,就像应用已经调用 service 的 stopSelf() 方法一样。

val intent = Intent(this,ServiceOne::class.java)
startForegroundService(intent)

Android 8.0之前启动后台service是调用startService方法,8.0之后需要调用startForegroundService方法来启动前台service,在系统创建service后,应用有5s的时间来调用该service的startForeground方法以显示新Service的用户可见通知,如果应用在此时间限制内未调用startForeground,则系统将停止此service并声明此应用为ANR。创建通知的改动也比较大,本文就不再说明,后面会单独写篇文章关于Notification通知。

虽然限制了后台服务的启动,这也杜绝了某些无良app在后台疯狂占用内存资源,主要还是影响到大部分应用保活手段,对于做普通应用来说个人觉得还好,如果需要后台启动,发送一个通知让用户知晓也并不觉得有太大的影响。

五、 IntentService

IntentService它是一个抽象类,并且继承自service。由于service是运行在主线程中的,其中不能做耗时的操作,否则就会导致ANR,如果真的需要在其中做耗时操作的话,必须创建一个新的线程。因此IntentService就可以满足这种需求。IntentService内部维护了一个工作线程,来处理耗时的操作,任务执行完成后就会自动停止,这样就无需我们手动去停止服务。另外的。可以多次启动IntentService,每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent方法中执行,并一次只会执行一个,执行完成之后才会继续执行下一个任务。

1、基本使用

接下来我们自定义一个类继承自IntentService,然后在MainActivity中新增一个按钮来启动服务,代码其实很简单,最主要就是在onHandleIntent方法中执行耗时操作,在其中让线程睡眠2s来模拟,我们只是简单的打印一下执行输出。

class MyIntentService(name: String) : IntentService(name) {

    constructor() : this("MyIntentService"){

    }

    override fun onCreate() {
        super.onCreate()
        println("MyIntentService ---> onCreate")
    }

    //将请求的Intent添加到工作队列里
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("MyIntentService ---> onStartCommand")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onHandleIntent(intent: Intent?) {
        println("MyIntentService ---> onHandleIntent")
        Thread.sleep(2000)
        val result = when (intent?.getStringExtra("name")) {
            "hello" -> "我执行的是hello这个任务"
            "world" -> "我执行的是world这个任务"
            else -> "我没有执行任何任务"
        }
        println("result:$result")
    }

    override fun onDestroy() {
        super.onDestroy()
        println("MyIntentService ---> onDestroy")
    }
}

在按钮中可以多次启动MyIntentService

var intentService: Intent? = null
intentService = Intent(this, MyIntentService::class.java)

intentServiceUseBtn?.setOnClickListener {
    intentService?.putExtra("name","hello")
    startService(intentService)
    intentService?.putExtra("name","world")
    startService(intentService)
    intentService?.putExtra("name","xxx")
    startService(intentService)
}

点击按钮,然后得到以下输出。可以看到onCreate方法还是只会执行一次,onStartCommandonHandleIntent方法会执行多次。也可以看出,任务的执行顺序也是一个接着一个的,当所有任务完成后,会自动调用onDestroy方法来销毁服务。

2、基本原理

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);
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }

    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

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

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

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

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

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

    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

上面就是IntentService的全部代码基于targetSdkVersion 27。首先看到的是它是一个抽象类,需要自己定义一个子类继承于它;再来看看构造方法,IntentService只提供了一个参数mName为String类型的构造方法,而这个mName就是后台线程的名称,我们在onCreate的方法中可以看到。

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

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

onCreate方法中有一个HandlerThread对象,其实它就是我们能够在服务中进行耗时操作的关键对象,HandlerThread它是一个线程,继承于Thread,这个对象就是对Thread + Handler的封装。我们知道在子线程中使用Handler,必须先要创建一个Looper对象,所以Google给我们封装了一个HandlerThread,使得无需手动调用Looper.prepare(),这一点可以在其run方法中就可以看出。

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

再回到onCreate方法,其中创建了一个ServiceHandler对象,并且获取到当前线程的Looper对象:mServiceLooper。

然后再看看onStartCommand方法,直接调用了onStart,然后在其中调用Handler的sendMessage方法,发送了一个Message消息,跟进sendMessage这个方法看看:

/**
  * Pushes a message onto the end of the message queue after all pending messages
  * before the current time. It will be received in {@link #handleMessage},
  * in the thread attached to this handler.
  *  
  * @return Returns true if the message was successfully placed in to the 
  *         message queue.  Returns false on failure, usually because the
  *         looper processing the message queue is exiting.
  */
public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}

从注释中我们可以看到一个关键信息,在这个Handler绑定的线程中,Handler中的handleMessage方法会收到消息。也就是说,handleMessage方法是在我们的当前子线程中执行,当然这个Handler就是我们IntentService中的ServiceHandler。那我们就直接看看ServiceHandler中的handleMessage方法。

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

方法中调用了onHandleIntent这个正是需要我们重写的抽象方法,这也就说明了可以在onHandleIntent方法中进行耗时操作,执行完之后会调用stopSelf方法停止自身,会回调service的onDestroy方法,这也就是service会自动停止的原因。

还剩下onBind方法,默认为我们返回了null,如果需要绑定当前Activity的话,需要自己重写此方法。用法就和之前一样,不再说明。

@Override
@Nullable
public IBinder onBind(Intent intent) {
    return null;
}

六、总结

Service是Android的四大组件之一 ,是运行在主线程中,并且长期运行在后台,不能做很耗时的操作,否则就会导致ANR,如果非要做耗时操作的话,还是要创建一个线程;IntentService是继承自Service的,里面封装了HandlerThread对象,无需自己手动创建Thread和Handler,并且IntentService是可以多次被创建的,当任务执行完成后会自动停止服务,也无需手动停止,所以需要在Service中做耗时操作,任务完成后不再使用服务的话,推荐使用IntentService。

git代码: github.com/leewell5717…

七、参考

Android官方文档——后台执行限制

Android Service使用详解

Android多线程:IntentService使用教程(含实例讲解)