前言
对于Service这个组件很多同学都会把它跟线程搞混,所以我们有必要先缕清一下基础知识。
线程:比进程更小的执行单元,每个进程可能有多条线程,线程需要放在一个 进程中才能执行,线程由程序负责管理,而进程则由系统进行调度!
多线程的理解:并行执行多个条指令,将CPU时间片按照调度算法分配给各个 线程,实际上是分时执行的,只是这个切换的时间很短,用户感觉到"同时"而已!进程和程序的区别:程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。
那Service跟线程有什么区别或者联系呢。其实一点联系都没有,Service只是一个支持长时间挂在后台运行的组件而已,在Service中可以开设多线程,其实从层次来说,Service跟线程就不是一个层面上的东西。
在安卓中一般Service都采用一个轮询的方式进行运行。轮询(Polling)是一种CPU决策如何提供周边设备服务的方式,又称“程控输入输出”(Programmed I/O)。轮询法的概念是:由CPU定时发出询问,依序询问每一个周边设备是否需要其服务,有即给予服务,服务结束后再问下一个周边,接着不断周而复始。
Service的启动方式
Android中使用Service的方式有主要有三种,第三种主要是第一第二种的结合使用:
BindService()启动Service
StartService()启动Service
还有一种不常使用的便是在service启动之后再去绑定service
创建Service
创建Service的方式非常简单,Android已经将Service封装成了一个很成熟的类,我们自定义Service只需要继承Service类即可。下面将给出一段示例代码,但是值得注意的是,我这里继承的类并不是Service类,而是IntentService。
这个IntentService看上去可能会有点懵逼,其实该类跟Service类在用法上区别不大,但是该类在很大程度上优化了Service类的使用。使用Service一般都不进行耗时操作,如若超过一秒没有响应就会发生报错,而IntentService则很好的解决了这个问题,该类让Service进行一些耗时操作成了可能,该类在启动服务之后会回调onHandleIntent方法,该方法相当于开多了一个子线程,所有耗时操作都在子线程中完成。该类其实本质上就是对Handle的封装。对于IntentService的具体介绍后面的文章会进一步描述,现在只需要知道创建Service的方法即可。
首先大概得介绍一下这个类里面的每个方法的用途。
onCreate:该方法只会在整个生命周期中调用一次,在第一次被创建后会立即回调该方法,后续无论绑定多少次Service或者启动多次Service,都不会在调用这个方法,而是会一直复用一开始创建的Service方法。
onDestory:当Service被关闭时会调用这个方法,该方法一样只会调用一次。
onStartCommand:这个方法只会在startService方式启动的情况下才会被回调,如若客户端多次调用startService,一样不会创建新的service对象,只会接着服用一开始已经创建好的对象。
onBind:这个方法会在通过bindService启动Service,绑定的时候进行调用,值得注意的是该方法是可以返回一个Binder对象的,这个Binder对象主要是进行进程之间的通信。
public class ThirdService extends IntentService {
private final static String TAG="ThirdService";
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public ThirdService(String name) {
super(name);
}
public ThirdService() {
super(TAG);
}
public class MyBinder extends Binder{
public String getTag(){
return TAG;
}
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.d(TAG,"onHandleIntent");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"onBind");
return new MyBinder();
}
@Override
public void onCreate() {
Log.d(TAG,"onCreate");
super.onCreate();
}
}
BindService
第一种直接使用BindService启动Service:bindService模式下的Service是与调用者相互关联的,可以理解为 "一条绳子上的蚂蚱",要死一起死,在bindService后,一旦调用者销毁,那么Service也立即终止!
简单来说就是,当只有一个客户端绑定了一个service的情况下,当客户端关闭该service也会被关闭。
如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用!
核心代码:
bindService(Intent Service,ServiceConnection conn,int flags)
service:通过该intent指定要启动的Service
conn:ServiceConnection对象,用户监听访问者与Service间的连接情况, 连接成功回调该对象中的onServiceConnected(ComponentName,IBinder)方法; 如果Service所在的宿主由于异常终止或者其他原因终止,导致Service与访问者间断开 连接时调用
flags:指定绑定时是否自动创建Service(如果Service还未创建), 参数可以是0(不自动创建),BIND_AUTO_CREATE(自动创建)
//目前安卓版本已经不允许通过隐式调用Service,只能进行显式调用
Intent intent1=new Intent(FunctionsActivity.this, ThirdService.class);
bindService(intent1,serviceConnection, Service.BIND_AUTO_CREATE);
-------------------------------------------------------------------------------------------
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
String tag = ((ThirdService.MyBinder) service).getTag();
Log.d(TAG,tag);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
这时候回调函数的调用顺序是 ThirdService#onCreate -> ThirdService#onCreate -> serviceConnection #onServiceConnected。
值得注意的是,onServiceDisconnected这个回调方法,当你主动调用unBindService这个方法解绑服务的时候,并不会回调这个方法。
还有一个Binder的问题,这是一种安卓特有的进程间通信机制,具体的后文会有一个总结。坚持一下,再看一会就到了。
startService
第二种直接使用startService启动Service:首次启动会创建一个Service实例,依次调用onCreate()和onStartCommand()方法,此时Service 进入运行状态,如果再次调用StartService启动Service,将不会再创建新的Service对象, 系统会直接复用前面创建的Service对象,调用它的onStartCommand()方法!
但这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期, 但是只要不调用stopService,那么Service还是会继续运行的!所以一般在使用这种方式启动服务的时候,一定要在活动生命周期摧毁的时候进行stopService操作。
//一样需要显式调用
Intent intent2=new Intent(FunctionsActivity.this, ThirdService.class);
startService(intent2);
StartService启动Service后bindService绑定
其实看这个标题描述就大概知道这个方式在代码上怎么表现。如果一个Service已经通过startService启动,接着再通过bindService进行绑定,这时候再调用unbindService解绑,最后再通过bindService绑定,这时候我们就得清晰的知道他的一个回调函数的走向了,搞懂这点基本上在流程上就彻底通了。
onCreate( )->onStartCommand( )->onBind( )->onUnbind( )->onRebind( )
这里值得注意的是,在我们学习BindService的时候,了解到当调用onUnbind的时候,Service会立刻进行onDestory的调用,但是这里并不会,在这里我们本来一开始进行了startService启动服务,所以Service就算解绑也不会立刻结束。
这里另外补充一点,可能大家会觉得第三种启动方式很鸡肋,感觉没有什么实用的价值。但是转念一想,这些东西如果没有实用价值怎么可能会被封装起来呢,对吧。有没有发现通过startService方式启动的service无法直接获取Binder,无法做到进程间的通信,而通过这种方式,startService也能进行Binder的通信!
Binder
上面一直在说的通信方式Binder到底是什么呢?Binder其实在日常的使用中还是很常见的,所以有必要好好学习一下。
首先我们要知道一个前提条件,进程与进程之间是无法直接通信的。故此Linux系统提供了一种RPC通信模型。RPC模型主要是以一种迁移线程的方式推进。迁移线程允许线程从一个任务“移动”到另外一个任务。在RPC期间,内核不会在其IPC(进程间通信)内核调用时阻塞客户机线程,而是安排他在服务器代码中继续执行。
其实上面还是有点生硬解释,如果你们有学习过Java的后端知识,学习到springcloud的时候,会发现不同微服务之间明明不同服务器却能互相调用服务的方法。这个RPC大概就是这个作用,在两个本来无法通信独立的进程之间搭起了一个桥梁,达到通信的作用。
RPC与IPC之间的区别
相同点:二者之间都可用于进程之间
不同点:RPC强调的是调用,一个进程直接调用另一个进程的方法,而IPC仅仅完成进程之间的互通信,没有函数调用功能。
总结来说,RPC其实就是添加了进程之间的函数调用功能的IPC
Android系统RPC与Binder的关系
Android的RPC并不需要实现不同主机或者不同操作系统间的远程调用。跟上面一样,Andorid的RPC=Binder进程间通信+在Binder基础上简历起来的进程间函数调用机制。文章来源:https://www.toymoban.com/news/detail-471650.html
对于Binder的使用,上面的代码事例中还是比较完整,可以划步到上面仔细看看哦,这边就不具体说了。文章来源地址https://www.toymoban.com/news/detail-471650.html
到了这里,关于安卓四大组件——Service服务(内含Binder的简单解释)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!