创建 Android 服务Creating Android Services
03/19/2018
本文内容
本指南讨论了 Xamarin Android 服务,它们是可让工作在没有活动用户界面的情况下执行的 Android 组件。服务通常用于在后台执行的任务,如使用计算、下载文件、播放音乐等。它介绍了服务适用的不同方案,并说明了如何实现它们来执行长时间运行的后台任务,以及如何为远程过程调用提供接口。This guide discusses Xamarin.Android services, which are Android components that allow work to be done without an active user interface. Services are very commonly used for tasks that are performed in the background, such as time consuming calculations, downloading files, playing music, and so on. It explains the different scenarios that services are suited for and shows how to implement them both for performing long-running background tasks as well as for providing an interface for remote procedure calls.
Android 服务概述Android Services Overview
移动应用程序与桌面应用程序不同。Mobile apps are not like desktop apps. 桌面具有详细的资源,如屏幕房地产、内存、存储空间和连接的电源,移动设备不会这样做。Desktops have copious amounts of resources such as screen real estate, memory, storage space, and a connected power supply, mobile devices do not. 这些约束强制移动应用的行为方式不同。These constraints force mobile apps to behave differently. 例如,移动设备上的小屏幕通常表示一次只显示一个应用(即活动)。For example, the small screen on a mobile device typically means that only one app (i.e. Activity) is visible at a time. 其他活动会移动到后台并推送到处于挂起状态的状态,在此状态下,它们无法执行任何工作。Other Activities are moved to the background and pushed into a suspended state where they cannot perform any work. 但是,这种情况下,由于 Android 应用程序处于后台,并不意味着应用程序无法继续工作。However, just because an Android application is in the background does not mean that it is impossible for app to keep working.
Android 应用程序由以下四个主要组件构成:活动、广播接收器、内容提供商_和_服务。Android applications are made up of at least one of the following four primary components: Activities, Broadcast Receivers, Content Providers, and Services. 活动是许多优秀 Android 应用程序的基础,因为它们提供允许用户与应用程序进行交互的 UI。Activities are the cornerstone of many great Android applications because they provide the UI that allows a user to interact with the application. 但是,在执行并发或后台工作时,活动并不总是最佳选择。However, when it comes to performing concurrent or background work, Activities are not always the best choice.
Android 中后台工作的主要机制是_服务_。The primary mechanism for background work in Android is the service. Android 服务是一个组件,用于在没有用户界面的情况下执行某些工作。An Android service is a component that is designed to do some work without a user interface. 服务可以下载文件、播放音乐,或将筛选器应用于映像。A service might download a file, play music, or apply a filter to an image. 服务还可用于 Android 应用程序之间的进程间通信(IPC)。Services can also be used for interprocess communication (IPC) between Android applications. 例如,一个 Android 应用可能使用来自其他应用的音乐播放机服务,或者一个应用可能会通过服务将数据(例如人员的联系信息)公开给其他应用。For example one Android app might use the music player service that is from another app or an app might expose data (such as a person's contact information) to other apps via a service.
服务及其执行后台工作的能力对于提供平滑的流畅用户界面至关重要。Services, and their ability to perform background work, are crucial to providing a smooth and fluid user interface. 所有 Android 应用程序都具有运行活动的_主线程_(也称为_UI 线程_)。All Android applications have a main thread (also known as a UI thread) on which the Activities are run. 为了保持设备响应能力,Android 必须能够以60帧/秒的速率更新用户界面。To keep the device responsive, Android must be able to update the user interface at the rate of 60 frames per second. 如果 Android 应用在主线程上执行过多工作,则 Android 会丢弃帧,这进而导致 UI 显示抖动(有时也称为_janky_)。If an Android app performs too much work on the main thread, then Android will drop frames, which in turn causes the UI to appear jerky (also sometimes referred to as janky). 这意味着在 UI 线程上执行的任何工作都应在两帧之间的时间范围内完成,大约为16毫秒(每60帧1秒)。This means that any work performed on the UI thread should complete in the time span between two frames, approximately 16 milliseconds (1 second every 60 frames).
为了解决这一问题,开发人员可以使用活动中的线程来执行一些会阻止 UI 的工作。To address this concern, a developer may use threads in an Activity to perform some work that would block the UI. 但是,这可能会导致问题。However, this could cause problems. 很有可能 Android 会销毁并重新创建活动的多个实例。It is very possible that Android will destroy and recreate the multiple instances of the Activity. 但是,Android 不会自动销毁线程,这可能会导致内存泄漏。However, Android will not automatically destroy the threads, which could result in memory leaks. 这种情况的一个典型示例是当设备旋转 – Android 时,会尝试销毁活动实例,然后重新创建一个新实例:A prime example of this is when the device is rotated – Android will try to destroy the instance of the Activity and then recreate a new one:
这是可能的内存泄漏 – ,由活动的第一个实例创建的线程仍将运行。This is a potential memory leak – the thread created by the first instance of the Activity will still be running. 如果线程具有对活动的第一个实例的引用,则这将阻止 Android 对对象进行垃圾回收。If the thread has a reference to the first instance of the Activity, this will prevent Android from garbage collecting the object. 但是,仍会创建活动的第二个实例(进而创建新的线程)。However, the second instance of the Activity is still created (which in turn might create a new thread). 迅速地多次旋转设备可能会耗尽所有 RAM,并强制 Android 终止整个应用程序以回收内存。Rotating the device several times in rapid succession may exhaust all the RAM and force Android to terminate the entire application to reclaim memory.
一般来说,如果要执行的工作应长于活动,则应创建一个服务来执行该操作。As a rule of thumb, if the work to be performed should outlive an Activity, then a service should be created to perform that work. 但是,如果工作仅适用于活动的上下文,则创建用于执行工作的线程可能更合适。However, if the work is only applicable in the context of an Activity, then creating a thread to perform the work might be more appropriate. 例如,为刚添加到照片库应用中的照片创建缩略图可能出现在服务中。For example, creating a thumbnail for a photo that was just added to a photo gallery app should probably occur in a service. 但是,在活动处于前台时,线程可能更适合播放一些音乐。However, a thread might be more appropriate to play some music that should only be heard while an Activity is in the foreground.
可以将后台工作分为两大类别:Background work can be broken down into two broad classifications:
长时间运行的任务 –这是正在进行的工作,直到显式停止。Long Running Task – This is work that is ongoing until explicitly stopped. _长时间运行的任务_的一个示例是流式传输音乐或必须监视从传感器收集的数据的应用程序。An example of a long running task is an app that streams music or that must monitor data collected from a sensor. 即使应用程序没有可见的用户界面,这些任务也必须运行。These tasks must run even though the application has no visible user interface.
定期任务 –(有时称为_作业_)定期任务是相对较短的持续时间(几秒钟),按计划运行(即一天一次,或在接下来的60秒内只需一次)。Periodic Tasks – (sometimes referred to as a job) A periodic task is one that is of relatively short in duration (several seconds) and is run on a schedule (i.e. once a day for a week or perhaps just once in the next 60 seconds). 例如,从 internet 下载文件或生成图像缩略图。An example of this is downloading a file from the internet or generating a thumbnail for an image.
有四种不同类型的 Android 服务:There are four different types of Android services:
绑定服务 –_绑定服务_是一种服务,它具有与之绑定的其他某个组件(通常为活动)。Bound Service – A bound service is a service that has some other component (typically an Activity) bound to it. 绑定服务提供了一个接口,该接口允许绑定组件和服务彼此交互。A bound service provides an interface that allows the bound component and the service to interact with each other. 如果没有更多的客户端绑定到服务,则 Android 会关闭服务。Once there are no more clients bound to the service, Android will shut the service down.
IntentService– IntentService 是类的专用子类 Service ,可简化服务的创建和使用。IntentService – An IntentService is a specialized subclass of the Service class that simplifies service creation and usage. 旨在 IntentService 处理单独的自治调用。An IntentService is meant to handle individual autonomous calls. 与可同时处理多个调用的服务不同, IntentService 更像是将_工作队列处理器_ – 工作排队等候, IntentService 每次在单个工作线程上处理一个作业。Unlike a service, which can concurrently handle multiple calls, an IntentService is more like a work queue processor – work is queued up and an IntentService processes each job one at a time on a single worker thread. 通常, IntentService 不会绑定到活动或片段。Typically, anIntentService is not bound to an Activity or a Fragment.
已启动服务 –_已启动的服务_是由其他某个 Android 组件(如活动)启动的服务,它将在后台持续运行,直到某些内容明确通知服务停止。Started Service – A started service is a service that has been started by some other Android component (such as an Activity) and is run continuously in the background until something explicitly tells the service to stop. 与绑定服务不同,已启动的服务没有任何直接绑定到它的客户端。Unlike a bound service, a started service does not have any clients directly bound to it. 出于此原因,设计启动的服务非常重要,这样就可以在必要时正确地重新启动服务。For this reason, it is important to design started services so that they may be gracefully restarted as necessary.
混合服务 –_混合服务_是一种服务,它具有已_启动服务_和_绑定服务_的特征。Hybrid Service – A hybrid service is a service that has the characteristics of a started service and a bound service. 当某个组件绑定到混合服务时,它可以启动,也可以由某个事件启动。A hybrid service can be started by when a component binds to it or it may be started by some event. 客户端组件可以或不绑定到混合服务。A client component may or may not be bound to the hybrid service. 混合服务将一直运行,直到显式告知它停止,或直到没有更多的客户端绑定到它。A hybrid service will keep running until it is explicitly told to stop, or until there are no more clients bound to it.
使用哪种类型的服务非常依赖于应用程序要求。Which type of service to use is very dependent on application requirements. 作为经验法则, IntentService 或绑定服务足以满足 Android 应用程序必须执行的大多数任务,因此应将首选项提供给这两种类型的服务之一。As a rule of thumb, an IntentService or a bound service are sufficient for most tasks that an Android application must perform, so preference should be given to one of those two types of services. IntentService对于 "一次" 任务(例如下载文件)来说,这是一个不错的选择,当需要频繁与活动/片段交互时,可以使用绑定服务。An IntentService is a good choice for "one-shot" tasks, such as downloading a file, while a bound service would be suitable when frequent interactions with an Activity/Fragment is required.
大多数服务在后台运行时,有一种特殊的子类别称为 "前台服务"。While most services run in the background, there is a special sub-category known as a foreground service. 这是一种服务,为用户执行一些工作(如播放音乐)提供了较高的优先级(与普通服务相比)。This is a service that is given a higher priority (compared to a normal service) to perform some work for the user (such as playing music).
还可以在同一台设备上的进程中运行服务,这有时称为_远程服务_或_进程外服务_()。It is also possible to run a service in its own process on the same device, this is sometimes referred to as a remote service or as an out-of-process service. 这确实需要更多的精力来创建,但在应用程序需要与其他应用程序共享功能时,可以使用此方法,并且在某些情况下,可以提高应用程序的用户体验。This does require more effort to create, but can be useful for when an application needs to share functionality with other applications, and can, in some cases, improve the user experience of an application.
Android 8.0 中的后台执行限制Background Execution Limits in Android 8.0
从 Android 8.0 (API 级别26)开始,Android 应用程序不再能够在后台自由地运行。Starting in Android 8.0 (API level 26), an Android application no longer have the ability to run freely in the background. 在前台,应用程序可以在不受限制的情况下启动并运行服务。When in the foreground, an app can start and run services without restriction. 当应用程序移到后台时,Android 会在一定时间内为应用授予启动和使用服务的时间。When an application moves into the background, Android will grant the app a certain amount of time to start and use services. 经过一段时间后,应用程序就不能再启动任何服务,任何已启动的服务都将被终止。Once that time has elapsed, the app can no longer start any services and any services that were started will be terminated. 此时,应用无法执行任何操作。At this point it is not possible for the app to perform any work. 如果满足以下条件之一,则 Android 会将应用程序视为处于前台:Android considers an application to be in the foreground if one of the following conditions are met:
存在可见的活动(已启动或已暂停)。There is a visible activity (either started or paused).
应用已启动前台服务。The app has started a foreground service.
另一个应用处于前台,并使用应用中的组件,此应用程序将在后台进行。Another app is in the foreground and is using components from an app that would be otherwise in the background. 例如,如果应用程序 A (在前台)绑定到应用程序 B 提供的服务,则会出现这种情况。在前台,应用程序 B 还将被视为前台,而 Android 不会将其终止。An example of this is if Application A, which is in the foreground, is bound to a service provided by Application B. Application B would then also be considered in the foreground, and not terminated by Android for being in the background.
在某些情况下,即使应用处于后台,Android 也会唤醒应用并放宽这些限制几分钟,允许应用执行一些工作:There are some situations where, even though an app is in the background, Android will wake up the app and relax these restrictions for a few minutes, allowing the app to perform some work:
应用收到高优先级 Firebase 云消息。A high priority Firebase Cloud Message is received by the app.
应用收到广播。The app receives a broadcast.
应用程序接收并执行以 PendingIntent 响应通知。The application receives and executes a PendingIntent in response to a Notification.
现有的 Xamarin 应用程序可能必须更改执行后台工作的方式,以避免 Android 8.0 上可能出现的任何问题。Existing Xamarin.Android applications may have to change how they perform background work to avoid any issues that might arise on Android 8.0. 下面是一些适用于 Android 服务的实用替代方案:Here are some practical alternatives to an Android service:
使用 Android 作业计划程序或Firebase 作业调度 – 程序将工作计划为在后台运行这两个库为应用程序提供了一个框架,用于将后台工作隔离到_作业_中,这是一个离散工作单元。Schedule work to run in the background using the Android Job Scheduler or the Firebase Job Dispatcher – These two libraries provide a framework for applications to segregate background work in to jobs, a discrete unit of work. 然后,应用程序可以通过操作系统来计划作业,以及有关作业运行时间的一些条件。Apps can then schedule the job with the operating system along with some criteria about when the job can run.
在前台 – 启动服务前台服务适用于应用必须在后台执行某些任务的情况,并且用户可能需要定期与该任务交互。Start the service in the foreground – a foreground service is useful for when the app must perform some task in the background and the user may need to periodically interact with that task. 前台服务将显示一个持续性通知,以使用户知道该应用正在运行后台任务,同时提供监视或与该任务交互的方法。The foreground service will display a persistent notification so that the user is aware that the app is running a background task and also provides a way to monitor or interact with the task. 例如,将播客的应用程序播放到用户,或下载播客节目,以便以后可以使用它。An example of this would be a podcasting app that is playing back a podcast to the user or perhaps downloading a podcast episode so that it can be enjoyed later.
使用高优先级 Firebase 云消息(FCM) –当 Android 收到应用的高优先级 FCM 时,它将允许该应用在后台运行服务一小段时间。Use a high priority Firebase Cloud Message (FCM) – When Android receives a high priority FCM for an app, it will allow that app to run services in the background for a short period of time. 这是具有在后台轮询应用的后台服务的好办法。This would be a good alternative to having a background service that polls an app in the background.
当应用进入前台 – 时延迟工作如果以前的解决方案都不可行,则应用程序必须开发自己的方法,以便在应用程序进入前台时暂停和恢复工作。Defer work for when the app comes into the foreground – If none of the previous solutions are viable, then apps must develop their own way to pause and resume work when the app comes to the foreground.
相关链接Related Links