安卓四大组件——Service服务(内含Binder的简单解释)

前言

对于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基础上简历起来的进程间函数调用机制。

对于Binder的使用,上面的代码事例中还是比较完整,可以划步到上面仔细看看哦,这边就不具体说了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值