四大组件之Service(一)-双子座的Service-Start Service与Bind Service

更新时间修改意见
2016-08-02陈敏

第1节 Service介绍

Service是安卓系统的四大组件之一。如果说Activity是专门为用户“看”的系统组件,那Service就是隐藏在角落默默付出的系统组件。

最典型的例子就是音乐播放器。音乐播放器应用中,播放音乐的组件就是一个Service。音乐播放器的界面就是一个提供了音乐控制方式的Activity,当我们点击Activity上的播放按钮之后,Activity通知播放器的Service组件,让Service组件开始播放音乐;之后即使用户选择退出了音乐播放器的Activity界面,音乐仍然在被播放着,并没有随着界面的退出而停止播放。

一个应用要拥有与用户交互的界面,它就要使用Activity组件;一个应用不需要与用户交互,只要在看不见的地方默默工作,它就要使用Service组件;不过只有很少的应用只会单独使用Service组件。

Service按照创建的方式进行分类,有两种:启动Service-start Service,绑定Service-bind Service。前者使用startService()运行,后者使用bindService()运行。

如果站在Service与触发Service运行的那个组件的角度区分,Service可以分成两种:本地Service,远程Service。


/*******************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/*******************************************************************/

第2节 Start Service和Bind Service

我们先从触发Service运行的角度来认识Service,有了整体的认识之后,我们再来看看远程Service和本地Service。

2.1 Start Service

其他组件通过调用startService()函数将Service运行起来,再通过调用stopService()函数让其停止运行。

单纯的使用这种形式的Service最为简单,它和它的调用者之间没有什么联系,调用者只是负责启动它和停止它,或者在启动它的时候通过Intent传递一点数据,除此之外,两者没有数据交换、没有其他的功能调用,这两个组件之间基本上互不影响。

设计这样的一个Service需要,

  1. 继承Android SDK提供的Service类,重写onBind()函数,让它返回空值;

    public class MyService extends Service {
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            //不需要调用者和Service有功能调用,返回空值
            return null;
        }
        ......
    }
  2. AndroidManifest.xml中,声明新创建的Service

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
    
        ......
        <application
            ......
            android:theme="@style/AppTheme">
    
            ......
            <!--声明新创建的Service-->
            <service
                android:name=".MyService"
                android:enabled="true"
                android:exported="true"></service>
        </application>
    
    </manifest>

使用这种Service也很简单。假设Activity A中有个按钮start,点击之后就调用startService;还有个按钮B-stop,点击之后就调用stopService

public void onClick(View v)
{

    switch (v.getId())
    {
        case R.id.start:
        {
            //启动Service
            Intent i = new Intent(this, MyService.class);
            startService(i);
        }
        break;

        case R.id.stop:
        {
            //停止Service
            Intent i = new Intent(this, MyService.class);
            stopService(i);
        }
        break;
    }
}

这里运行Service的时候,是通过Intent明确指定被运行的Service。这种明确指定启动哪个Service的方式叫做Service的显示调用。与之对应的还有隐式调用。我们稍后来详细介绍。

2.2 Bind Service

其他组件通过调用bindService()绑定Service,让它运行起来;再通过调用unbindService()解除绑定。

这种形式的Service与调用者之间通常有功能调用或者频繁的数据交换,调用者会向Service发出请求让Service进行特定的操作,并返回结果。

设计这样的一个Service需要,

  1. 继承Android SDK提供的Service类,

    public class MyService extends Service {
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            //暂时返回空值,写下来将进行改造
            return null;
        }
        ......
    }
  2. 实现一个自定义的Binder,让它这个继承Binder类。

    Binder可以将Service与调用者联系起来,在Binder中提供的方法,就是Service对外提供的方法。

    组件和Service之间的调用是通过Binder来进行的。我们可以把Binder看作是一个连接其他组件和Service的桥梁,它的实现原理是什么,我们暂时不用去关心,只要知道这样用就可以了。

    public class MyService extends Service {
    
        ......
    
        //创建一个自定义的Binder
        public class MyServiceIBinder extends Binder {
            //提供给其他组件调用的方法
            public void function1(int param){
                //调用Service中真正实现功能的方法
                innerFunction1(param);
            }
        }
    
        //真正实现功能的方法
        private void innerFunction1(int param) {
    
        }
    
        //创建Binder实例
        private final IBinder mBinder = new MyServiceIBinder();
    
        @Override
        public IBinder onBind(Intent intent) {
            //当组件bindService()之后,将这个Binder返回给组件使用
            return mBinder;
        }
    
        ......
    }
  3. AndroidManifest.xml中,声明新创建的Service

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
    
        ......
        <application
            ......
            android:theme="@style/AppTheme">
    
            ......
            <!--声明新创建的Service-->
            <service
                android:name=".MyService"
                android:enabled="true"
                android:exported="true"></service>
        </application>
    
    </manifest>

其他组件使用这个Service的时候,

  1. 创建一个ServiceConnection,当绑定Service之后,在onServiceConnected()中会得到Service返回的Binder;如果Service遇到异常情况退出时,会通过onServiceDisconnected()通知绑定它的组件。

    private ServiceConnection mServiceConnection = new ServiceConnection()
    {
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //这里的service参数,就是Service当中onBind()返回的Binder
            //获取访问Service的桥梁-MyServiceIBinder
            MyService.MyServiceIBinder bridge = (MyService.MyServiceIBinder) service;
    
            //通过桥梁就可以调用到Service提供到函数了
            bridge.function1(0);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            //当Service遇到异常情况退出时,会通过这里通知绑定过它的组件
        }
    };

    获得了MyService.MyServiceIBinder之后,我们就可以向调用普通函数那样,调用到Service对外提供的接口函数了。

    需要注意的是,如果用户主动解除绑定,onServiceDisconnected()是不会被触发的。

  2. 假设Activity A中有个按钮,点击之后就调用bindService;还有个按钮B,点击之后就调用unbindService

    public void onClick(View v)
    {
    
        switch (v.getId())
        {
            case R.id.start:
            {
                Intent i = new Intent(this, MyService.class);
                bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE);
            }
            break;
    
            case R.id.stop:
            {
                unbindService(mServiceConnection);
            }
            break;
        }
    }

    这里同样采用的是对Service的显示调用。

2.3 混合模式

Service并不是只能给一个组件使用,它可以同时服务于多个组件。
所以一个Service既可以是Start Service,也可以是Bind Service。只要把两者需要实现的地方都实现了就行。组件A可以通过startService()运行一个Service,组件B可以通过bindService()再次运行同一个Service

2.4 显式调用和隐式调用

Activity一样,Service有两种被调用的方式,显式调用和隐式调用。

2.4.1 显式调用

通过Intent明确的指定要运行哪个Service,这就是显式调用。
就好像给指定的个人发货,写下接收方具体的名字和地址。

设计显式调用,

//明确的指定了要运行的Service的类名、包名
Intent i = new Intent(this, MyService.class);
bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE);

通常,应用中的组件启动自己应用中的Service,可以采用这样的方式,

Intent i = new Intent(this, MyService.class)
startService(i);

//或者

Intent i = new Intent(this, MyService.class)
bindService(i, mServiceConnection, Context.BIND_AUTO_CREATE);

2.4.2 隐式调用

如果是应用A的组件要使用应用B的Service,通常会使用到隐式调用,不明确的告知要启动的Service是什么,而是通过IntentAction Name让操作系统自己匹配最合适的响应者。

就好像给某个机构发货,只需要发送给某个机构,但不需要知道这个机构中具体是哪个人。

设计隐式调用,

  1. AndroidManifest.xml文件中为这个Service指定一个过滤器,为过滤器指定一个Action name

    ......
    <application
        ......
        android:theme="@style/AppTheme">
    
        ......
        <!--声明新创建的Service-->
        <service
         android:name=".MyService"
         android:enabled="true"
         android:exported="true">
            <!--指定一个过滤器,为过滤器指定一个Action name-->
            <intent-filter>
                <action android:name="custom.service.remote" />
            </intent-filter>
    
        </service>
    </application>
  2. 应用A的组件,要使用这个Service的时候,就可以,

    Intent i = new Intent("custom.service.remote");
    
    //Android5.0版本的以上的系统上要添加这一项,用来指定Service所在的包名
    i.setPackage("xxx.xxx.xxx");
    startService(i);
    
    或者
    
    Intent i = new Intent("custom.service.remote");
    
    //Android5.0版本的以上的系统上要添加这一项,用来指定Service所在的包名
    i.setPackage("xxx.xxx.xxx");
    bindService(i, mServiceConnection2, Context.BIND_AUTO_CREATE);

注意,对于Android5.0版本的以上的系统上要设置Intent发送目标的包名。因为从Android5.0开始,不允许隐式启动Service了。


/*******************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。

*另外,我们还推出了Arduino智能硬件相关的教程,您可以在我们的网店跟我学Arduino编程中购买相关硬件。同时也感谢大家对我们这些码农的支持。

*最后再次感谢各位读者对安豆的支持,谢谢:)
/*******************************************************************/

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值