Android Service基础
Posted ITRenj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Service基础相关的知识,希望对你有一定的参考价值。
- 《Android Service基础》
- 《Android Service回调和配置》
- 《Android Service aidl使用及进阶》
- 《Android Service更多知识》
- 《Android 中的 IntentService 类详解》
- 《Android Service aidl分析》
- 《Android Service 流程分析》
简单介绍
Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。服务可以分为前台、后台和绑定三种类型。
分类
前台服务
前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示通知。即使用户停止与应用的交互,前台服务仍会继续运行。
后台服务
后台服务执行用户不会直接注意到的操作。例如,如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务。
注意:如果您的应用面向 API 级别 26 或更高版本,当应用本身未在前台运行时,系统会对运行后台服务施加限制。
绑定服务
当应用组件通过调用 bindService() 绑定到服务时,服务即处于绑定状态。绑定服务会提供客户端-服务器接口,以便组件与服务进行交互、发送请求、接收结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
说明
- 虽然分开讨论启动服务和绑定服务,但服务可以同时以这两种方式运行,换言之,它既可以是启动服务(以无限期运行),亦支持绑定。唯一的问题在于您是否实现一组回调方法:onStartCommand()(让组件启动服务)和 onBind()(实现服务绑定)。
- 无论服务是处于启动状态还是绑定状态(或同时处于这两种状态),任何应用组件均可像使用 Activity 那样,通过调用 Intent 来使用服务(即使此服务来自另一应用)。不过,可以通过清单文件将服务声明为私有服务(通过添加 android:exported 属性并将其设置为 false),并阻止其他应用访问该服务。
- 服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非通过 android:process=“progress name” 另行指定)。 如果服务将执行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或联网),则应通过在服务内创建新线程来完成这项工作。通过使用单独的线程降低发生“应用无响应”(ANR) 错误的风险,而应用的主线程仍可继续专注于运行用户与 Activity 之间的交互。
基本使用
创建服务
创建服务必须创建 Service 的子类(或使用它的一个现有子类),同时Service也是Android四大组件之一,所以需要在清单文件中进行注册。
public class LocalService extends Service
@Nullable
@Override
public IBinder onBind(Intent intent)
Log.i(TAG, "onBind: ");
return null;
@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 super.onStartCommand(intent, flags, startId);
@Override
public void onDestroy()
super.onDestroy();
Log.i(TAG, "onDestroy: ");
清单文件中进行配置:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".local.LocalService" />
</application>
启动服务
应用组件(如 Activity)可通过调用 startService()
方法并传递 Intent 对象(指定服务并包含待使用服务的所有数据)来启动服务。服务会回调 onStartCommand()
方法(onStart()
方法也会调用,已过时),在 onStartCommand()
方法接收此 Intent。
停止服务
服务启动后,其生命周期即独立于启动它的组件。即使系统已销毁启动服务的组件,该服务仍可在后台无限期地运行。因此,服务应在其工作完成时通过调用 stopSelf()
来自行停止运行,或者由另一个组件通过调用 stopService()
来将其停止。如果服务同时处理多个对 onStartCommand()
的请求,则不应在处理完一个启动请求之后停止服务,因为服务可能已收到新的启动请求(在第一个请求结束时停止服务会终止第二个请求)。为避免此问题,可以使用 stopSelf(int)
确保服务停止请求始终基于最近的启动请求。换言之,在调用 stopSelf(int)
时,需要传递与停止请求 ID 相对应的启动请求 ID(传递给 onStartCommand()
的 startId)。此外,如果服务在调用 stopSelf(int)
之前收到新启动请求,则 ID 不匹配,服务也不会停止。
绑定服务
如需与 Activity 或者其他应用组件中的服务进行交互,或需要通过进程间通信 (IPC) 向其他应用公开某些应用功能,则应创建绑定服务。要创建绑定服务,需要通过实现 onBind()
回调方法返回 IBinder,从而定义与服务进行通信的接口。然后,其他应用组件通过调用 bindService()
方法来启动并绑定服务,并通过ServiceConnection
的回调方法获取到的IBinder开始调用与服务相关的方法。
绑定服务只用于与其绑定的应用组件,多个客户端可以同时绑定到服务。完成与服务的交互后,客户端应该要通过调用 unbindService()
来取消绑定。如果没有绑定到服务的客户端或所有绑定的客户端都通过 unbindService()
方法取消绑定了,则系统会销毁该服务。而不必像通过 onStartCommand()
启动的服务那样,以相同方式停止绑定服务。
创建绑定Service
// 定义绑定服务方法
public interface ILocalBinder
String getServiceMsg();
void serviceShowToast(String msg);
// 创建服务
public class LocalBinderService extends Service
private final String TAG = LocalService.class.getSimpleName();
private class LocalBinder extends Binder implements ILocalBinder
@Override
public String getServiceMsg()
return new Random().nextInt(100) + 1 + " service info";
@Override
public void serviceShowToast(String msg)
Toast.makeText(LocalService.this, "service: " + msg, Toast.LENGTH_SHORT).show();
@Nullable
@Override
public IBinder onBind(Intent intent)
Log.i(TAG, "onBind: ");
return new LocalBinder();
// ...
操作Service
private ILocalBinder iLocalBinder;
public void binderService(Context context)
ServiceConnection conn = new ServiceConnection()
@Override
public void onServiceConnected(ComponentName name, IBinder service)
iLocalBinder = (ILocalBinder) service;
@Override
public void onServiceDisconnected(ComponentName name)
;
// 绑定服务
Intent intent = new Intent(context, LocalBinderService.class);
context.bindService(intent, conn, Service.BIND_AUTO_CREATE);
// 调用Service的方法
String serviceMsg = iLocalBinder.getServiceMsg();
iLocalBinder.serviceShowToast("调动Service方法");
// 解绑服务
context.unbindService(conn);
在前台运行服务
前台服务是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。前台服务必须为状态栏提供通知,将其放在运行中的标题下方。这意味着除非将服务停止或从前台移除,否则不能清除该通知。
注意: 在 Android 9(API 级别 28)或更高版本中使用前台服务,必须请求 FOREGROUND_SERVICE
权限。这是一种普通权限,因此,系统会自动为请求权限的应用授予此权限,否则系统会抛出 SecurityException
让服务运行在前台
通过调用Service的 startForeground(int id, Notification notification)
方法【参数1:通知标识(不能为 0)参数2:用于状态栏的 Notification】,可以让服务运行在前台。
移出前台运行的服务
通过调用Service的 stopForeground(boolean removeNotification)
。指定是否需同时移除状态栏通知。此方法并不会停止服务。但是,如果在服务运行于前台时将其停止,则通知也会随之移除。
特别注意
-
不要为服务Intent声明过滤器
为确保应用的安全性,在启动 Service 时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。使用隐式 Intent 启动服务存在安全隐患,因为您无法确定哪些服务会响应 Intent,而用户也无法看到哪些服务已启动。从 Android 5.0(API 级别 21)开始,如果使用隐式 Intent 调用
bindService()
,则系统会抛出异常。 -
Android 8适配
在Android 8.0 以上系统不允许后台应用创建后台服务。 因此引入了一种全新的方法,即通过
Context.startForegroundService()
方法在前台启动新服务,通过调用该方法,在系统创建服务后,应用有五秒的时间来调用该服务的startForeground()
方法以显示新服务的用户可见通知,如果应用在此时间限制内未调用startForeground()
,则系统将停止服务并声明此应用为 ANR。
以上是关于Android Service基础的主要内容,如果未能解决你的问题,请参考以下文章