如需转载请评论或简信,并注明出处,未经允许不得转载

目录

前言
Service是Android四大组件之一,但是由于实际开发中可能没有Activity使用的频繁,有的同学对Service的一些使用和某些细节可能不是特别清楚。没关系,这篇文章将带你更加全面的了解Service
为什么要使用Service
从字面意思上看来,Service
是服务的意思,我们很容易联想到它是一个帮助我们在后台完成一些任务的组件,那么它和Thread
有什么区别呢?
Thread的定义
Thread
:程序执行的最小单元,它是分配CPU的基本单位
Thread的生命周期
-
新建,new Thread()
-
就绪,排队等候cpu资源
-
运行,run()
-
死亡,执行完毕或被杀死
-
阻塞,由于某种原因,正在运行的线程让出cpu,并暂停执行
Thread的特点(重要)
Thread
子线程独立于Activity
,Activity
很难对线程进行控制,当Activity
被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity
中创建的子线程,另一个Activity
无法对其进行操作
当我们需要使用Thread
连续不停地每隔一段时间就要连接服务器一次做某种同步,那么这个Thread
就需要在Activity
退出后也运行,同时需要对这个Thread
进行控制,这时候我们要怎么办?
没错!使用Service
就可以解决了
什么是Service?
-
Service
既不是一个线程,Service
通常运行在当成宿主进程的主线程中,所以在Service
中进行一些耗时操作就需要在Service
内部开启线程去操作,否则会引发ANR异常 - 也不是一个单独的进程,除非在清单文件中声明时指定进程名,否则
Service
所在进程就是application所在进程 -
Service
可以不需要UI就在后台运行,不用管开启它的页面是否被销毁,只要进程还在就可以在后台运行 -
Service
是Android中的四大组件,使用它一定要在AndroidManifest.xml
中声明
Service的启动方式与生命周期
Service有三种启动方式
-
startService
-
bindService(类似于C/S结构)
-
startService&bindService同时调用

startService
startService步骤
- 定义一个类继承
Service
- 在
Manifest.xml
文件中配置该Service
- 使用
Context
的startSerice(intent)
方法启动该Service
- 不再使用时,调用
stopService(intent)
方法停止该服务
private Intent mStartIntent;
public void btnStartService(View view) {
mStartIntent = new Intent(this, MyService.class);
startService(mStartIntent);
}
public void btnStopService(View view) {
if (mStartIntent != null) {
stopService(mStartIntent);
}
}
startService特点
-
startService
方式启动Service
不会调用到onBind()
-
startService
可以多次调用,但是只有第一次调用才会执行onCreate()
,之后每次调用都会直接执行onStartCommand()
,onStartCommand()
执行次数与startService
调用次数一致 -
不管调用多少次
startService
,只需要调用一次stopService
就结束 -
如果
startService
后没有调用stopSelf
或者stopService
,则Service
一直存活并运行在后台,直到进程被杀死
bindService
bindService步骤
- 定义一个类继承
Service
- 在
Manifest.xml
文件中配置该Service
- 创建
Binder
子类,返回给客户端即Activity使用,提供数据交换的接口 - 在
Service
的onBind()
中返回创建的Binder
子类对象 - 在
Activity
中定义用于接收Binder
的ServiceConnection
- 在
onServiceConnected()
中拿到Service
对象后,就可以调用Service
内部的公有方法 - 使用
Context
的bindSerice(intent,ServiceConnection,flags)
方法启动该Service
-
Activity
被销毁,或者主动掉调用unbindService()
,Service的生命周期结束
//创建Binder子类,返回给客户端即Activity使用,提供数据交换的接口
public class MyBinder extends Binder {
//声明一个方法,getService。(提供给客户端调用)
MyService getService() {
return MyService.this;
}
}
//在Service的onBind()中返回创建的Binder子类对象
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return new MyBinder();
}
//在Activity中定义用于接收Binder的ServiceConnection
mConn = new ServiceConnection() {
/**
* 与服务端交互的接口方法,绑定服务的时候被回调,单这个方法获得绑定Service传递过来的IBinder对象
* 通过IBinder对象,实现宿主和Service交互
* */
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.i(TAG, "绑定成功调用:onServiceConnected");
//获取Binder
MyService.MyBinder binder = (MyService.MyBinder) iBinder;
//拿到Service对象后,就可以调用Service内部的公有方法
mService = binder.getService();
}
/**
* 正常情况下是不被调用的,他的调用时机是当Service服务被意外销毁时
* 进程crash或被kill
* */
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.i(TAG, "服务被销毁:onServiceDisconnected");
}
};
//bindService
public void btnBindService(View view) {
Intent intent = new Intent(this, MyService.class);
bindService(intent, mConn, Service.BIND_AUTO_CREATE);
}
//unbindService
public void btnUnBindService(View view) {
if (mService != null) {
mService = null;
unbindService(mConn);
}
}
bindService特点
- 由于
bindService
是异步执行的,所以需要额外构建一个ServiceConnection
对象用与接收bindService
的状态,同时还要指定bindService
的类型 -
bindService()
也可以调用多次,与startService()
不同,多次调用bindService()
,onBind()
和onServiceConnected()
只执行一次 - 主动调用
unbindService()
并不会回到onServiceDisconnected()
,只有当Service
服务被意外销毁时(如进程crash或者内存资源不足被kill),这个方法才被自动调用。可以用adb shell kill pid
或kill service
来测试 - 通过
bindService()
方式启动Service
,Activity
可以拿到Service
对象,所以可以调用Service
内部的公有方法
startService&bindService
针对同一个Service
,我们既可以是启动服务的状态(即启动后无限运行下去直到进程被杀死),也可以绑定服务状态(即绑定对象销毁,服务也销毁),那么就可能会出现启动服务和绑定服务的先后顺序问题
- 先
startService()
,后bindService()
启动服务状态不会转化为绑定服务状态,即使调用unbindService()
后,服务依然会以启动服务状态在后台运行,直到收到stopService()
指令
- 先
bindService()
,后startService()
绑定服务状态会转化为启动服务状态,即使之前绑定的Activity
销毁了,服务还是会继续运行下去,直到收到stopService()
指令
小结
-
启动服务状态的优先级会高于绑定服务端状态,因为绑定服务是要依托于我们的Activity的,而启动服务只需要依靠Service本身以及内存的一些情况
-
不管先后顺序如何,Android系统仅仅会为一个Service创建一个Service对象,所有操作的都是同一个Service对象
-
当同时调用
startService()
和bindService()
后,需要分别调用stopService()
和unbindService()
,Service
才会走onDestroy()
一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁
异步Service — IntentService
Service
通常运行在当成宿主进程的主线程中,所以在Service
中进行一些耗时操作就需要在Service
内部开启线程去操作,否则会引发ANR异常- 通过
startService
形式开启Service
时,如果不主动调用stopService
,Service
将在后台一直运行
为了解决这个两个问题,Android系统帮我们封装了IntentService
类。下面我们通过源码来看看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执行异步操作
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();
//HanderThread是Thread类的子类,内部封装了Looper,方便我们在子线程中使用Handler
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
//把HandlerThread持有的looper对象转交给mServiceHandler
//即 mServiceHandler就可以执行异步任务了
mServiceHandler = new ServiceHandler(mServiceLooper);
}
//onStartCommand之后执行
@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
内部有一个工作线程HanderThread
,(有关HanderThread
的知识可以看HandlerThread使用及源码解析
),并通过这个HandlerThread中的looper创建了一个Handler对象,然后将Intent以Message的方式从主线程发送到子线程,这样onHandleIntent()
就在子线程中执行,可以执行耗时操作
相同点:
-
继承自
Service
,与Service
的启动方式是一样的,具有Service
各种特性 -
IntentService
也可以多次启动,但是每次启动会将任务添加到工作队列中,每次只会执行一个工作线程
不同点:
- 在使用时将不再需要实现
onStartCommand()
,同时需要实现onHandleIntent()
来执行异步任务 - 当消息队列中所有任务执行完成后,
IntentService
会在内部自动调用stopSelf()
关闭自己,不用手动调用stopService()
总结
本文讲了Service
与Thread
的区别与应用场景,Service
的启动方式以及不同启动方式分别对应的生命周期,同时也介绍了用于异步任务处理的IntentService类。对于Service
原理感兴趣的可以继续看Service详解(原理篇)
网友评论