Service学习笔记01-启动方式与生命周期
Posted 双木青橙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Service学习笔记01-启动方式与生命周期相关的知识,希望对你有一定的参考价值。
0 系列汇总
- Service学习笔记01-启动方式与生命周期
- Service学习笔记02-实战 startService 与bindService
- Service学习笔记03- 前台服务实战
- Service学习笔记04- 其他服务实现方式与替代方式
1 Service的使用场景
Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件,服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行了进程间通信(IPC)。
以下是三种不同不同的服务类型。
-
前台
前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。 -
后台
后台服务执行用户不会直接注意到的操作。例如,如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务 -
绑定
当应用组件通过调用bindService()
绑定到服务时,服务处于绑定状态,绑定服务会提供C/S接口,以便组件与服务进行交互、发送请求、接收结果,甚至是利用进程间通信(IPC)跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可同时绑定到服务,但是要全部取消绑定后,该服务即会被销毁。
2 Service的两种启动方式
无论是startService
还是bindService
都是通过Intent来显式指定,且不要为服务声明Intent 过滤器。使用隐式Intent启动服务存在安全隐患,因为您无法确定哪些服务会影响Intent,而用户也无法看到哪些服务已启动。从android 5.0 (API 21)开始,如果使用隐式Intent调用bindService()
,则系统会抛出异常。
Service 必须在AndroidManifest清单文件中定义,系统不会识别和运行任何未声明的服务。完整的可参考,android:name
属于是唯一必需的属性,用于指定服务的类名。发布应用后,请确保此类名不变,以避免因依赖显式Intent来启动或者绑定服务不可用的风险。
一个典型的Service 声明见如下所示:
<application
<service
android:name="com.hl.bindertest.service.LocalService"
android:exported="false"
android:process=":Daemon"/>
</application>
- android:name
实现服务的 Service 子类的名称。此名称应该是一个完全限定类名称,如(“com.example.project.RoomService”)。不过,作为一种简写形式,如果名称的第一个字符是句点,(如“.RoomService”),则会将其附加到 元素中指定的软件包名称(不建议采用此方式)。发布应用后,不能更改此名称(除非您已设置 android:exported=“false”),且修改后将应用调用处也同步修改。 - android:process
将运行服务的进程的名称。通常,应用的所有组件都会在为应用创建的默认进程中运行。它与应用软件包的名称相同。 元素的 process 属性可以为所有组件设置不同的默认值。即只有需要另起一个进程运行引服务时,通过以冒号(:)开头的名称指定一个新进程的名称,否则process属性不需要定义 - android:exported
如果为true,则表示其他应用的组件可以调用服务或者与之交互。建立如果明确不需要提供给其他三方应用使用,则务必将其置为false
2.1 通过startService()
启动服务
startService 是不能与Service进行交互的,在调用startService启动服务后,与调用者就无关联了,服务会依次执行onCreate()
和onStartCommand()
方法,直到被stopService()
停止服务或者自身通过stopSelf()
停止服务
调用方法所示所示:
// 应用内可直接通过class文件指定要启动的Service
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
// 也可通过packageName和Service 全路径名称指定
Intent intent = new Intent();
intent.setClassName("com.hl.bindertest", "com.hl.bindertest.service.LocalService");
startService(startIntent);
2.2 通过binService()
绑定
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
private ServiceConnection connection = new ServiceConnection()
@Override
public void onServiceDisconnected(ComponentName name)
Log.d(TAG, "on ServiceDisConnected executor");
@Override
public void onServiceConnected(ComponentName name, IBinder service)
Log.d(TAG, "on onServiceConnected executor");
downloadBinder = (MyService.DownloadBinder) service;
;
bindService(bindIntent, connection, BIND_AUTO_CREATE);
// 在使用完成后,及时解绑服务
unbindService(connection);
3 Service 的回调方法与生命周期
- 说明:
- Service 是系统生成的天然的单例,如果
onCreate()
方法只会执行一次,如果Service已经被启动,onCreate()
不会再被调用 - 需要注意的是,Service的
onCreate()
、onBind()
等方法都是默认执行在主线程中的,也就是说,我们需要在服务的内部手动创建子线程,并在这里执行具体的任务,否则有可能出现ANR的问题 startService()
和stopService()
是成对出现的(当然也可通过stopSelf)()
); bindService()和unBindService()也是成对出现的。在Service使用过程中要注意及时解绑和停止Service,严格控制Service的生命周期才能有效避免功耗和内存的问题。
3.1 重要的回调方法说明
onCreate()
**首次创建服务时,**系统会(在调用onStartCommand()
或者onBind()
之前)调用此方法来执行一次性设置程序。如果服务已经在运行,则不会调用此方法onStartCommand()
当其他组件通过startService
的方式启动Service时,执行此方法时,服务即会启动并可在后台无限期运行。如果您实现此方法,则在服务工作完成后,您需要负责通过调用stopSelf()
或者stopService
来停止服务。(如果您只想提供绑定,则无需实现此方法)onBind()
当另一个组件想要与服务(例如执行RPC)时,系统会通过调用bindService()
来调用此方法。在此方法的实现中,您必须通过返回IBinder
提供一个接口,以供客户端用来与服务进行通信。请务必实现此方法;但是,如果您并不希望允许绑定,则应返回null。onDestory
当不再使用服务且准备将其销毁时,系统会调用此方法。服务应通过实现此方法来清理任何资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。
如果组件通过调用startService
启动服务,则服务会一直运行,直到通过stopSelf()
自行停止运行,或由其他服务通过调用stopService将其停止为止。
3.2生命周期
- Service是典型的单例模式,
onCreate()
只会执行一次,已经启动后再次调用startService
和bindService
并不会再次执行onCreate()
方法
3.2.1 只通过startService启动服务的生命周期
3.2.2 只通过bindService启动服务的生命周期
3.2.3 同时使用startService()启动服务、BindService()绑定服务的生命周期
需要同时解绑和停止服务才会最终执行onDestory()
将服务销毁
以上是关于Service学习笔记01-启动方式与生命周期的主要内容,如果未能解决你的问题,请参考以下文章
Service学习笔记02-实战 startService 与bindService