service详解

1. 什么是service

Service是一个可以在后台执行长时间操作而不使用用户界面的应用组件。那么问题来了,既然它不使用用户界面,那么它怎么知道应该什么时候开始执行什么操作呢?答案是——它可以与其他的引用组件形成一些联系,从而可以根据其传来的信息在合适的时候执行合适的操作。

一般来讲,这种联系分为两种:startService()以及bindService()。这两种联系都可以使得一个service开始运行,但是在其他方面有着诸多不同。

service启动service的方式停止service的方式service与启动它的组件之间的通信方式service的生命周期
startService在其他组件中调用startService()方法后,服务即处于启动状态service中调用stopSelf()方法,或者其他组件调用stopService()方法后,service将停止运行没有提供默认的通信方式,启动service后该service就处于独立运行状态一旦启动,service即可在后台无限期运行,即使启动service的组件已被销毁也不受其影响,直到其被停止
bindService在其他组件中调用bindService()方法后,服务即处于启动状态所有与service绑定的组件都被销毁,或者它们都调用了unbindService()方法后,service将停止运行可以通过 ServiceConnection进行通信,组件可以与service进行交互、发送请求、获取结果,甚至是利用IPC跨进程执行这些操作当所有与其绑定的组件都取消绑定(可能是组件被销毁也有可能是其调用了unbindService()方法)后,service将停止

2. 如何创建一个service?

关于这个,每本Android入门的书籍基本上都会有所提及,基本上也正如它们所述:

  • 创建一个类继承自Service(或它的子类,如IntentService),重写里面的一些关键的回调方法,如onStartCommand(),onBind()等

  • 在Manifests文件里面为其声明,并根据需要配置一些其他属性。

  • onCreate()

    在每个service的生命周期中这个方法会且仅会调用一次,并且它的调用在onStartCommand()以及onBond()之前,我们可以在这个方法中进行一些一次性的初始化工作。
    
  • onStartCommand()

    当其他组件通过startService()方法启动service时,此方法将会被调用。
    
  • onBind()

    当其他组件通过bindService()方法与service相绑定之后,此方法将会被调用。这个方法有一个IBinder的返回值,这意味着在重写它的时候必须返回一个IBinder对象,它是用来支撑其他组件与service之间的通信的——另外,如果你不想让这个service被其他组件所绑定,可以通过在这个方法返回一个null值来实现。
    
  • onDestory()

    这是service一生中调用的最后一个方法,当这个方法被调用之后,service就会被销毁。所以我们应当在这个方法里面进行一些资源的清理,比如注册的一些监听器什么的。
    

在Manifests文件里进行声明的时候,只有android:name属性是必须要有的,其他的属性都可以没有。但是有的时候适当的配置可以让我们的开发进行地更加顺利,所以了解一下注册一个service可以声明哪些属性也是很有必要的。

<service
    android:enabled=["true" | "false"]
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:isolatedProcess=["true" | "false"]
    android:label="string resource"
    android:name="string"
    android:permission="string"
    android:process="string" >
</service>
  • android:enabled

     如果为true,则这个service可以被系统实例化,如果为false,则不行。默认为true
    
  • android:exported

    如果为true,则其他应用的组件也可以调用这个service并且可以与它进行互动,如果为false,则只有与service同一个应用或者相同user ID的应用可以开启或绑定此service。它的默认值取决于service是否有intent filters。如果一个filter都没有,就意味着只有指定了service的准确的类名才能调用,也就是说这个service只能应用内部使用——其他的应用不知道它的类名。这种情况下exported的默认值就为false。反之,只要有了一个filter,就意味着service是考虑到外界使用的情况的,这时exported的默认值就为true
    
  • android:icon

    一个象征着这个service的icon
    
  • android:isolatedProcess

    如果设置为true,这个service将运行在一个从系统中其他部分分离出来的特殊进程中,我们只能通过Service API来与它进行交流。默认为false。
    
  • android:label

    显示给用户的这个service的名字。如果不设置,将会默认使用<application>的label属性。
    
  • android:name

    这个service的路径名,例如“com.lypeer.demo.MyService”。这个属性是唯一一个必须填的属性。
    
  • android:permission

     其他组件必须具有所填的权限才能启动这个service。
    
  • android:process

    service运行的进程的name。默认启动的service是运行在主进程中的。
    

下面是一个例子

public class ServiceDemo extends Service {

    private static final String TAG = "ServiceDome";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        //只在service创建的时候调用一次,可以在此进行一些一次性的初始化操作
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        //当其他组件调用startService()方法时,此方法将会被调用
        //在这里进行这个service主要的操作
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        //当其他组件调用bindService()方法时,此方法将会被调用
        //如果不想让这个service被绑定,在此返回null即可
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        //service调用的最后一个方法
        //在此进行资源的回收
        super.onDestroy();
    }
}
<!--in manifests -->
<service android:name=".ServiceDemo"/>

3. 如何启动service?

  1. startService()

    另一个组件通过调用startService()方法,就可以启动一个特定的service,并且这将导致service中的onStartCommand()方法被调用。在调用startService()方法的时候,其他组件需要在方法中传递一个intent参数,然后service将会在onStartCommand()中接收这个intent,并获取一些数据。比如此时某个Activity要将一些数据存入数据库中,我就可以通过intent把数据传入service,然后让service去进行连接数据库,存储数据等操作,而此时用户可以执行其他的任何操作——甚至包括销毁那个Activity——这并不会影响service存储数据这件事。

    当一个service通过这种方式启动之后,它的生命周期就已经不受启动它的组件影响了,它可以在后台无限期的运行下去,只要service自身没有调用stopSelf()并且其他的组件没有调用针对它的stopService()。

    另外,如果确定了使用这种方式启动service并且不希望这个service被绑定的话,那么也许除了传统的创建一个类继承service之外我们有一个更好的选择——继承IntentService。

    如果是扩建Service类的话,通常情况下我们需要新建一个用于执行工作的新线程,因为默认情况下service将工作于应用的主线程,而这将会降低所有正在运行的Activity的性能。而IntentService就不同了。它是Service的子类,它使用工作线程来注意的处理所有的startService请求。如果你不要求这个service要同时处理多个请求,那么继承这个类显然要比直接继承Service好到不知道哪里去了——IntentService已经做了这些事:

    • 创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent

    • 创建工作队列,用于将一个 Intent 逐一传递给 onHandleIntent() 实现,这样的话就永远不必担心多线程问题了

    • 在处理完所有启动请求后停止服务,从此妈妈再也不用担心我忘记调用 stopSelf() 了

    • 提供 onBind() 的默认实现(返回 null)

    • 提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现

    例子:

    //现在在一个Activity里面
    Intent intent = new Intent(MainActivity.this , IntentServiceDemo.class);
    startService(intent)
        public class IntentServiceDemo extends IntentService {
    
            public IntentServiceDemo(String name) {
                super(name);
                //构造方法
            }
    
            @Override
            protected void onHandleIntent(Intent intent) {
                //在这里根据intent进行操作
            }
        }
  2. bindService()

    这是一种比startService更复杂的启动方式,同时使用这种方式启动的service也能完成更多的事情,比如其他组件可向其发送请求,接受来自它的响应,甚至通过它来进行IPC等等。我们通常将绑定它的组件成为客户端,而称它为服务器。
    
    如果要创建一个支持绑定的service,我们必须要重写它的onBind()方法。这个方法会返回一个IBinder对象,它是客户端用来和服务器进行交互的接口。而要得到IBinder接口,我们通常有三种方式:继承Binder类,使用Messenger类,使用AIDL
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值