Android 四大组件(二)Service

一段时间不用,知识点就会忘,所以整理下一些基本的知识点,加深下印象,便于以后复习。这篇说一下Android中四大组件之一Service的使用。


1 Service简介

Service是可以在后台执行长时间运行的应用程序组件,不提供用户界面。另一个应用程序组件可以启动一个服务,即使用户切换到另一个应用程序,它也将在后台继续运行。另外,组件可以绑定到一个服务来与它进行交互,甚至执行进程间通信(IPC)。例如,服务可以从后台处理网络事务,播放音乐,执行文件I / O或与内容提供商交互。

服务基本上可以采取两种形式:

  • Started
    当应用程序组件(如Activity)通过调用startService()启动服务时,服务将“启动”。一旦启动,服务可以在后台无限期运行,即使启动它的组件被销毁。通常,启动服务执行单个操作,并且不会将结果返回给调用者。例如,它可能会通过网络下载或上传文件。操作完成后,服务应该停止。
  • Bound
    当应用程序组件通过调用bindService()绑定到一个服务时,服务是“绑定的”。绑定服务提供客户端 - 服务器接口,允许组件与服务交互,发送请求,获取结果,甚至可以通过进程间通信(IPC)进行交互。只要绑定了一个应用程序组件,绑定的服务就会运行。多个组件可以同时绑定到服务,但是当所有组件都解除绑定时,服务将被销毁。

虽然通常单独讨论这两种类型的服务,但您的服务可以以两种方式工作 - 它可以启动(无限期运行)并允许绑定。这只是一个实现几个回调方法的问题:onStartCommand()允许组件启动它并onBind()允许绑定。

无论您的应用程序是启动,绑定还是两者兼容,任何应用程序组件都可以使用该服务(即使是单独的应用程序),也可以以任何组件可以使用活动的方式启动它Intent。但是,您可以将该服务声明为私有,在清单文件中,并阻止其他应用程序的访问。

注意: 服务在主机进程的主线程中运行 - 服务不会创建自己的线程,并且不会在单独的进程中运行(除非另有指定)。 这意味着,如果您的服务将进行任何CPU密集型工作或阻塞操作(如MP3播放或网络连接),则应在服务中创建一个新的线程来完成此工作。 通过使用单独的线程,您将降低应用程序不响应(ANR)错误的风险,并且应用程序的主线程可以保留专用于与您的活动的用户交互。


2 创建Service

创建服务,必须创建一个Service(或其一个现有子类)的子类。在实现中,您需要覆盖处理服务生命周期关键方面的一些回调方法,并提供一种机制,使组件绑定到服务(如果适用)。应该覆盖的最重要的回调方法是:

  • onStartCommand()
    当另一个组件(如Activity)通过调用startService()请求启动该服务时,系统将调用此方法。一旦执行此方法,该服务将启动并可以无限期地在后台运行。如果您实现这方法,您的责任是通过调用stopSelf()或stopService()停止服务。(如果只想提供绑定,则不需要实现此方法。)
  • onBind()
    当另一个组件通过调用bindService()与服务绑定时,系统会调用此方法。在实现此方法时,必须提供一个客户端用于与服务通信的接口,方法是返回IBinder。您必须始终实现此方法,但如果不想允许绑定,则应返回null。
  • onCreate()
    系统调用该方法时,在首次创建服务,执行一次性建立过程(它在onStartCommand()或 onBind()调用之前)。如果服务已经运行,则不会调用此方法。
  • onDestroy()
    当服务不再使用并被销毁时,系统调用此方法。应该实现这一点,以清理任何资源,如线程,注册的听众,接收者等。这是服务接收的最后一个呼叫。
public class ExampleService extends Service {
    private static String TAG = "ExampleService";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG,"onCreate");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        return START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"onBind");
        return null;
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG,"onDestroy");
    }
}

如果组件通过调用startService()(其导致调用onStartCommand())启动服务,则服务将保持运行,直到它停止自身stopSelf()或通过调用停止它stopService()。
请注意,onStartCommand()方法必须返回一个整数。整数是一个值,描述系统在系统杀死服务时如何继续服务。返回值onStartCommand()必须是以下常量之一:

  • START_NOT_STICKY  
    如果系统在onStartCommand()返回后杀死了服务,并且没有待处理的intent,则会将Service从启动状态中删除,并且不会重新创建服务了,直到明确的调用(Context.startService(Intent))。 当服务不再是必需的,并且应用程序能够简单地重启那些未完成的工作时,这是避免服务运行的最安全的选项。
  • START_STICKY
    如果系统在onStartCommand()返回后杀死了服务,则将重新创建服务并调用onStartCommand(),但不会再次传入上一个intent, 而是用null intent来调用onStartCommand() 。除非有待处理的intent启动服务,在这种情况下,这些intent会继续传递。这适用于不执行命令但无限期运行并等待工作的媒体播放器(或类似服务)。
  • START_REDELIVER_INTENT
    如果系统在onStartCommand()返回后杀死了服务,则将重新创建服务并调用onStartCommand()(传递上一个发送给服务的intent),任何待处理的intent也都会依次送入。这适用于那些需要立即恢复工作的活跃服务,比如下载文件。

如果一个组件调用 bindService()创建服务(和onStartCommand()被不叫),那么服务只只要组件绑定到它运行。一旦服务从所有客户端解除绑定,系统就会销毁它。

Android系统只会在内存不足时强制停止服务,并且必须为具有用户焦点的活动恢复系统资源。如果服务被绑定到具有用户焦点的活动,则不太可能被杀死,并且如果该服务被声明在前台运行(稍后讨论),则几乎不会被杀死。否则,如果服务启动并长时间运行,系统会随着时间的推移降低后台任务列表中的位置,并且服务将非常容易被杀死 。

3 在清单中声明服务

像Activity(和其他组件)一样,必须在清单文件中声明应用程序的的所有服务。
要声明您的服务,请添加<service>元素作为<application>元素的子 元素。例如:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

可以在<service>元素中包含其他属性,例如启动服务所需的权限以及服务应运行的进程等进程。该android:name属性是唯一必需的属性,它指定服务的类名。

android:name---服务类名
android:label --- 服务的名字,如果此项不设置,那么默认显示的服务名则为类名
android:icon----服务的图标
android:permission-申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务
android:process--表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字
android:enabled--如果此项设置为 true,那么 Service 将会可以被系统启动,false,表示此Service不可以被启动(也就是不能使用)。不设置默认此项为true(网上好多person都说默认值位false,这是不对的。)
android:exported--表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

为了确保您的应用程序安全,始终在启动或绑定您时使用明确的意图,Service并且不为服务声明意图过滤器。如果关键是您允许开始使用哪些服务的模糊性,您可以为您的服务提供意图过滤器,并从中排除组件名称Intent,然后您必须为intent设置包setPackage(),这样可以确定目标服务。

另外,您可以通过包含android:exported属性和设置为"false"来确保您的服务仅适用于您的应用。即使使用明确的意图,这有效地阻止其他应用程序启动您的服务。


4 开始服务

诸如Activity之类的应用程序组件可以通过调用startService()并传递一个指定服务的Intent来启动服务,并包括要服务使用的任何数据。该服务Intent在onStartCommand()方法中接收到该intent。

Intent intent = new Intent(this, ExampleService.class);
startService(intent);

该startService()方法立即返回,Android系统调用该服务的onStartCommand()方法。如果服务尚未运行,则系统首先呼叫onCreate(),然后调用onStartCommand()。

当服务启动时,它具有独立于启动服务的组件的生命周期,并且服务可以无限期地在后台运行,即使启动它的组件被销毁。started的服务必须管理自己的生命周期。也就是说,系统不会停止或销毁服务,除非它必须恢复系统内存,并且服务在onStartCommand()返回后继续运行。因此,服务应该通过调用stopSelf()停止自己当完成工作时,或者另一个组件可以通过调用stopService()来停止它。


5 绑定服务

应用程序组件通过调用bindService()以创建长期连接来绑定的服务。
当您希望通过应用程序中的Activity和其他组件通过service进行交互,或通过进程间通信(IPC)将某些应用程序的功能暴露给其他应用程序时,应创建绑定服务。
要创建bound的服务,您必须实现onBind()回调方法来返回一个IBinder,IBinder用于定义与服务通信的接口。其他应用程序组件可以调用bindService()来检索该接口并开始调用该服务的方法。 该服务仅用于为与其绑定的应用程序组件提供服务,因此当没有组件绑定到服务时,系统会将其销毁。
要创建绑定的服务,首先要做的是定义一个接口,指定客户端如何与服务进行通信。服务和客户端之间的这个接口必须是一个实现,IBinder是您的服务必须从onBind()回调方法返回的。一旦客户端收到IBinder,它可以开始通过该接口与服务进行交互。
多个客户端可以一次绑定到该服务。当客户端完成与服务的交互时,它会调用unbindService()解除绑定。一旦没有客户端绑定到服务,系统会销毁该服务。

实现绑定服务有多种方法,并且实现比起始服务更复杂,下一篇讲一下其多种方法。


6 service的生命周期

这里写图片描述

Service生命周期(从创建到销毁时)可以遵循两个不同的路径:

  • start Service
    当另一个组件调用startService()时,创建该服务。然后该服务无限期地运行,并且必须通过调用来停止自身stopSelf()。另一个组件也可以通过调用来停止服务stopService()。当服务停止时,系统会销毁它
  • bind Service
    当另一个组件(客户端)调用bindService()时,创建该服务。然后,客户端通过IBinder接口与服务进行通信。客户端可以通过调用来关闭连接 unbindService()。多个客户端可以绑定到同一个服务,当它们全部解除绑定时,系统会销毁该服务。(服务不需要自行停止。)

这两条路径并不完全分开。也就是说,您可以绑定到已经通过startService()启动的Service。例如,背景音乐Service可以通过调用startService()启动与Intent标识要播放的音乐。后来,可能当用户想要对播放器进行一些控制或获取关于当前歌曲的信息时,Activity可以通过调用bindService()来绑定到服务。在这种情况下,stopService()或者stopSelf()实际上并不停止服务,直到所有客户端解除绑定。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容