public abstract class Service
extends ContextWrapper
implements ComponentCallbacks2
java.lang.Object | |||
↳ | android.content.Context | ||
↳ | android.content.ContextWrapper | ||
↳ | android.app.Service |
Known Direct Subclasses |
Known Indirect Subclasses |
服务是一种应用程序组件,表示应用程序希望在不与用户交互的情况下执行长时间运行的操作,或者为其他应用程序提供的功能。 每个服务类必须在其包AndroidManifest.xml
具有相应的<service>
声明。 服务可以用Context.startService()
和Context.bindService()
开始。
请注意,与其他应用程序对象一样,服务在主机进程的主线程中运行。 这意味着,如果你的服务要做任何CPU密集型(如MP3播放)或阻塞(如网络)操作,它应该产生自己的线程来完成这项工作。 有关详情,请参阅Processes and Threads 。 IntentService
类可用作服务的标准实现,该服务具有自己的线程,用于安排要完成的工作。
涵盖的主题包括:
有关如何创建服务的详细讨论,请阅读 Services开发人员指南。
关于服务类的大多数混淆事实上都围绕着什么 不是 :
因此服务本身其实非常简单,提供了两个主要功能:
Context.startService()
, which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it. Context.bindService()
, which allows a long-standing connection to be made to the service in order to interact with it. 当实际创建一个服务组件时,出于以上任何一种原因,系统实际上所做的一切就是实例化该组件,并在主线程上调用其onCreate()
和任何其他适当的回调onCreate()
。 由服务来实现这些适当的行为,例如创建一个辅助线程来完成它的工作。
请注意,由于服务本身非常简单,因此您可以根据需要简单或复杂地将其与交互进行交互:将其视为您直接调用方法的本地Java对象(如 Local Service Sample所示 ),以提供完整使用AIDL的可远程接口。
系统可以运行服务有两个原因。 如果有人调用Context.startService()
那么系统将检索服务(如果需要,创建它并调用其方法onCreate()
),然后使用客户端提供的参数调用其方法onStartCommand(Intent, int, int)
。 该服务将在此时继续运行,直到Context.stopService()
或stopSelf()
被调用。 请注意,对Context.startService()的多次调用不会嵌套(尽管它们会导致对onStartCommand())进行多次相应调用),因此无论启动多少次,服务都会停止一次Context.stopService()或stopSelf () 叫做; 但是,服务可以使用他们的stopSelf(int)
方法来确保服务不会停止,直到开始的意向处理完毕。
对于启动的服务,根据从onStartCommand()返回的值,他们可以决定运行两个额外的主要操作模式: START_STICKY
用于根据需要显式启动和停止的服务,而使用START_NOT_STICKY
或START_REDELIVER_INTENT
对于在处理发送给它们的任何命令时应该只保持运行的服务。 有关语义的更多详细信息,请参阅链接的文档。
客户端也可以使用Context.bindService()
获取服务的持续连接。 如果服务尚未运行(同时调用onCreate()
),则同样会创建该服务,但不会调用onStartCommand()。 客户端将收到服务从其onBind(Intent)
方法返回的IBinder
对象,从而允许客户端回拨该服务。 只要建立连接(无论客户是否保留对服务的IBinder的引用),该服务就会继续运行。 通常IBinder返回的是一个复杂的界面,已经written in aidl 。
服务既可以启动,也可以绑定连接。 在这种情况下,只要服务启动, 或者与Context.BIND_AUTO_CREATE
标志有一个或多个连接,系统就会继续运行服务。 一旦这两种情况都不成立,服务的onDestroy()
方法被调用并且服务被有效终止。 从onDestroy()返回后,所有清理(停止线程,取消注册接收者)应该完成。
在清单的<service>
标记中声明时,可以强制全局访问服务。 通过这样做,其他应用程序将需要在其自己的清单中声明相应的<uses-permission>
元素,以便能够启动,停止或绑定到该服务。
从GINGERBREAD
,使用Context.startService(Intent)
,您还可以在意图上设置Intent.FLAG_GRANT_READ_URI_PERMISSION
和/或Intent.FLAG_GRANT_WRITE_URI_PERMISSION
。 这将授予服务临时访问意向中的特定URI。 访问将保持到服务已为该启动命令或更晚的命令调用stopSelf(int)
,或者直到服务已完全停止。 这适用于授予对尚未请求保护服务权限的其他应用程序的访问权限,或者甚至在根本不导出服务时。
另外,服务可以在执行该呼叫之前通过调用 checkCallingPermission(String)
方法来保护具有权限的单个IPC调用。
有关权限和安全性的更多信息,请参阅Security and Permissions文档。
只要服务已经启动或客户端绑定了,Android系统就会尝试保留托管服务的进程。 当内存不足并需要终止现有进程时,承载该服务的进程的优先级将高于以下几种可能性:
如果该服务目前处于执行代码 onCreate()
, onStartCommand()
,或 onDestroy()
方法,那么托管进程将是一个前台进程,确保代码不会被杀死才能执行。
如果服务已经启动,那么它的托管过程被认为比在屏幕上当前对用户可见的任何过程重要,但比任何不可见的过程更重要。 因为用户通常只能看到几个进程,所以这意味着服务不应该在内存不足的情况下被终止。 但是,由于用户并不直接了解后台服务,因此在该状态下它被认为是有效的杀手,并且您应该准备好实现此目的。 特别是,长期运行的服务将越来越可能被杀死,并且如果它们保持足够长的时间,它们将被保证被杀死(并在适当情况下重新启动)。
如果有客户绑定到该服务,那么该服务的托管过程永远不会比最重要的客户更不重要。 也就是说,如果其中一个客户对用户可见,那么该服务本身被认为是可见的。 该方法在客户端的重要性,影响到服务的重要性,可通过调整BIND_ABOVE_CLIENT
, BIND_ALLOW_OOM_MANAGEMENT
, BIND_WAIVE_PRIORITY
, BIND_IMPORTANT
,并BIND_ADJUST_WITH_ACTIVITY
。
已启动的服务可以使用startForeground(int, Notification)
API将服务置于前台状态,系统认为该服务是用户主动注意的内容,因此不适合在内存不足时进行查杀。 (从理论上讲,服务在当前前台应用程序的极端内存压力下被杀死,但实际上这不应该成为问题。)
请注意,这意味着大部分时间您的服务正在运行,如果系统在内存压力很大的情况下可能会被系统中止。 如果发生这种情况,系统将稍后尝试重新启动服务。 这样做的一个重要后果是,如果您实现onStartCommand()
以安排工作异步完成或在另一个线程中完成,那么您可能希望使用START_FLAG_REDELIVERY
让系统为您重新提供一个意图,以便它不会丢失,如果您的服务在处理时被杀害。
与服务运行在同一进程中的其他应用程序组件(例如Activity
)当然可以提高整个流程的重要性,而不仅仅是服务本身的重要性。
服务最常见的用途之一是作为辅助组件与应用程序的其他部分一起运行,与其他组件一样运行。 .apk的所有组件都运行在相同的进程中,除非另有明确说明,所以这是一种典型的情况。
以这种方式使用时,通过假设组件处于相同的过程中,可以极大地简化它们之间的交互:服务的客户可以简单地将它从其接收的IBinder转换为由服务发布的具体类。
这里显示了这种服务使用的一个例子。 首先是服务本身,在绑定时发布自定义类:
public class LocalService extends Service { private NotificationManager mNM; // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. private int NOTIFICATION = R.string.local_service_started; /** * Class for clients to access. Because we know this service always * runs in the same process as its clients, we don't need to deal with * IPC. */ public class LocalBinder extends Binder { LocalService getService() { return LocalService.this; } } @Override public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. We put an icon in the status bar. showNotification(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("LocalService", "Received start id " + startId + ": " + intent); return START_NOT_STICKY; } @Override public void onDestroy() { // Cancel the persistent notification. mNM.cancel(NOTIFICATION); // Tell the user we stopped. Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show(); } @Override public IBinder onBind(Intent intent) { return mBinder; } // This is the object that receives interactions from clients. See // RemoteService for a more complete example. private final IBinder mBinder = new LocalBinder(); /** * Show a notification while this service is running. */ private void showNotification() { // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = getText(R.string.local_service_started); // The PendingIntent to launch our activity if the user selects this notification PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LocalServiceActivities.Controller.class), 0); // Set the info for the views that show in the notification panel. Notification notification = new Notification.Builder(this) .setSmallIcon(R.drawable.stat_sample) // the status icon .setTicker(text) // the status text .setWhen(System.currentTimeMillis()) // the time stamp .setContentTitle(getText(R.string.local_service_label)) // the label of the entry .setContentText(text) // the contents of the entry .setContentIntent(contentIntent) // The intent to send when the entry is clicked .build(); // Send the notification. mNM.notify(NOTIFICATION, notification); } }
完成后,现在可以编写直接访问正在运行的服务的客户端代码,例如:
private LocalService mBoundService; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. mBoundService = ((LocalService.LocalBinder)service).getService(); // Tell the user about this for our demo. Toast.makeText(Binding.this, R.string.local_service_connected, Toast.LENGTH_SHORT).show(); } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. mBoundService = null; Toast.makeText(Binding.this, R.string.local_service_disconnected, Toast.LENGTH_SHORT).show(); } }; void doBindService() { // Establish a connection with the service. We use an explicit // class name because we want a specific service implementation that // we know will be running in our own process (and thus won't be // supporting component replacement by other applications). bindService(new Intent(Binding.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; } void doUnbindService() { if (mIsBound) { // Detach our existing connection. unbindService(mConnection); mIsBound = false; } } @Override protected void onDestroy() { super.onDestroy(); doUnbindService(); }
如果您需要能够编写一个可以在远程进程中与客户端进行复杂通信的服务(不仅仅是使用 Context.startService
向其发送命令),那么您可以使用 Messenger
类而不是写入完整的AIDL文件。
这里显示了一个使用Messenger作为客户端界面的服务示例。 首先是服务本身,绑定时将Messenger发布到内部处理程序:
public class MessengerService extends Service { /** For showing and hiding our notification. */ NotificationManager mNM; /** Keeps track of all current registered clients. */ ArrayList<Messenger> mClients = new ArrayList<Messenger>(); /** Holds last value set by a client. */ int mValue = 0; /** * Command to the service to register a client, receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client where callbacks should be sent. */ static final int MSG_REGISTER_CLIENT = 1; /** * Command to the service to unregister a client, ot stop receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client as previously given with MSG_REGISTER_CLIENT. */ static final int MSG_UNREGISTER_CLIENT = 2; /** * Command to service to set a new value. This can be sent to the * service to supply a new value, and will be sent by the service to * any registered clients with the new value. */ static final int MSG_SET_VALUE = 3; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_REGISTER_CLIENT: mClients.add(msg.replyTo); break; case MSG_UNREGISTER_CLIENT: mClients.remove(msg.replyTo); break; case MSG_SET_VALUE: mValue = msg.arg1; for (int i=mClients.size()-1; i>=0; i--) { try { mClients.get(i).send(Message.obtain(null, MSG_SET_VALUE, mValue, 0)); } catch (RemoteException e) { // The client is dead. Remove it from the list; // we are going through the list from back to front // so this is safe to do inside the loop. mClients.remove(i); } } break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); @Override public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. showNotification(); } @Override public void onDestroy() { // Cancel the persistent notification. mNM.cancel(R.string.remote_service_started); // Tell the user we stopped. Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show(); } /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } /** * Show a notification while this service is running. */ private void showNotification() { // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = getText(R.string.remote_service_started); // The PendingIntent to launch our activity if the user selects this notification PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0); // Set the info for the views that show in the notification panel. Notification notification = new Notification.Builder(this) .setSmallIcon(R.drawable.stat_sample) // the status icon .setTicker(text) // the status text .setWhen(System.currentTimeMillis()) // the time stamp .setContentTitle(getText(R.string.local_service_label)) // the label of the entry .setContentText(text) // the contents of the entry .setContentIntent(contentIntent) // The intent to send when the entry is clicked .build(); // Send the notification. // We use a string id because it is a unique number. We use it later to cancel. mNM.notify(R.string.remote_service_started, notification); } }
如果我们想让这个服务在远程进程中运行(而不是标准的.apk),我们可以在其manifest标签中使用 android:process
来指定一个:
<service android:name=".app.MessengerService" android:process=":remote" />
请注意,此处选择的名称“remote”是任意的,如果您需要其他进程,则可以使用其他名称。 ':'前缀将名称附加到包的标准进程名称。
完成后,客户端现在可以绑定到服务并向其发送消息。 请注意,这允许客户端注册以接收消息:
/** Messenger for communicating with service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mIsBound; /** Some text view we are using to show state information. */ TextView mCallbackText; /** * Handler of incoming messages from service. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MessengerService.MSG_SET_VALUE: mCallbackText.setText("Received from service: " + msg.arg1); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. We are communicating with our // service through an IDL interface, so get a client-side // representation of that from the raw service object. mService = new Messenger(service); mCallbackText.setText("Attached."); // We want to monitor the service for as long as we are // connected to it. try { Message msg = Message.obtain(null, MessengerService.MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); // Give it some value as an example. msg = Message.obtain(null, MessengerService.MSG_SET_VALUE, this.hashCode(), 0); mService.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even // do anything with it; we can count on soon being // disconnected (and then reconnected if it can be restarted) // so there is no need to do anything here. } // As part of the sample, tell the user what happened. Toast.makeText(Binding.this, R.string.remote_service_connected, Toast.LENGTH_SHORT).show(); } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; mCallbackText.setText("Disconnected."); // As part of the sample, tell the user what happened. Toast.makeText(Binding.this, R.string.remote_service_disconnected, Toast.LENGTH_SHORT).show(); } }; void doBindService() { // Establish a connection with the service. We use an explicit // class name because there is no reason to be able to let other // applications replace our component. bindService(new Intent(Binding.this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; mCallbackText.setText("Binding."); } void doUnbindService() { if (mIsBound) { // If we have received the service, and hence registered with // it, then now is the time to unregister. if (mService != null) { try { Message msg = Message.obtain(null, MessengerService.MSG_UNREGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // There is nothing special we need to do if the service // has crashed. } } // Detach our existing connection. unbindService(mConnection); mIsBound = false; mCallbackText.setText("Unbinding."); } }
Inherited constants |
---|
From class android.content.Context
|
From interface android.content.ComponentCallbacks2
|
Public constructors |
|
---|---|
Service() |
Public methods |
|
---|---|
final Application |
getApplication() 返回拥有此服务的应用程序。 |
abstract IBinder |
onBind(Intent intent) 将通信信道返回给服务。 |
void |
onConfigurationChanged(Configuration newConfig) 设备配置在组件运行时发生更改时由系统调用。 |
void |
onCreate() 服务第一次创建时由系统调用。 |
void |
onDestroy() 由系统调用以通知服务它已不再使用并正在被删除。 |
void |
onLowMemory() 这在整个系统内存不足时调用,并且主动运行的进程应该修剪内存使用情况。 |
void |
onRebind(Intent intent) 当新的客户端连接到服务时调用,之前它已被通知所有已断开其 |
void |
onStart(Intent intent, int startId) 此方法在API级别5中已弃用。 |
int |
onStartCommand(Intent intent, int flags, int startId) 每次客户端通过调用 |
void |
onTaskRemoved(Intent rootIntent) 如果服务当前正在运行并且用户已经删除了来自服务应用程序的任务,则会调用该服务。 |
void |
onTrimMemory(int level) 当操作系统确定进程从其进程中删除不需要的内存是一个好时机时调用。 |
boolean |
onUnbind(Intent intent) 当所有客户端与服务发布的特定接口断开连接时调用。 |
final void |
startForeground(int id, Notification notification) 使该服务在前台运行,提供正在进行的通知,以便在此状态下向用户显示。 |
final void |
stopForeground(int flags) 从前台状态中删除此服务,如果需要更多内存,则允许它被终止。 |
final void |
stopForeground(boolean removeNotification) |
final void |
stopSelf() 停止服务,如果它以前开始。 |
final void |
stopSelf(int startId) 旧版本的 |
final boolean |
stopSelfResult(int startId) 如果最近一次启动的时间是 startId,请停止服务。 |
Protected methods |
|
---|---|
void |
dump(FileDescriptor fd, PrintWriter writer, String[] args) 将服务的状态打印到给定的流中。 |
Inherited methods |
|
---|---|
From class android.content.ContextWrapper
|
|
From class android.content.Context
|
|
From class java.lang.Object
|
|
From interface android.content.ComponentCallbacks2
|
|
From interface android.content.ComponentCallbacks
|
int START_CONTINUATION_MASK
由onStartCommand(Intent, int, int)
返回的onStartCommand(Intent, int, int)
说明如何在服务onStartCommand(Intent, int, int)
继续服务。 可能是START_STICKY
, START_NOT_STICKY
, START_REDELIVER_INTENT
,或START_STICKY_COMPATIBILITY
。
常量值:15(0x0000000f)
int START_FLAG_REDELIVERY
如果意图是先前交付的意图的重新交付,则此标志设置为 onStartCommand(Intent, int, int)
,因为此服务先前已返回 START_REDELIVER_INTENT
但在为该意图调用 stopSelf(int)
之前已被杀死。
常数值:1(0x00000001)
int START_FLAG_RETRY
如果意图是重试,则该标志被设置为 onStartCommand(Intent, int, int)
,因为原始尝试从未到达或从 onStartCommand(Intent, int, int)
返回。
常量值:2(0x00000002)
int START_NOT_STICKY
从onStartCommand(Intent, int, int)
返回的onStartCommand(Intent, int, int)
:如果此服务的进程在启动时(从onStartCommand(Intent, int, int)
返回后)被onStartCommand(Intent, int, int)
,并且没有新的启动意向传递给它,则使服务退出启动状态,直到未来明确致电Context.startService(Intent)
。 该服务将不会收到带有空Intent的onStartCommand(Intent, int, int)
调用,因为如果没有未完成的要传递的内容,它将不会重新启动。
这种模式对于想要开始工作的人来说是有意义的,但在内存压力下可以停下来,并且会在稍后再明确地开始自己做更多的工作。 这种服务的一个例子就是轮询来自服务器的数据:它可以通过让闹钟启动其服务来安排闹钟来每N分钟轮询一次。 当它从报警中调用onStartCommand(Intent, int, int)
,它会在N分钟后安排一个新的报警,并产生一个线程进行联网。 如果在执行该检查时它的进程被终止,则该服务将不会重新启动,直到警报关闭。
常量值:2(0x00000002)
int START_REDELIVER_INTENT
从onStartCommand(Intent, int, int)
返回onStartCommand(Intent, int, int)
:如果此服务的进程在启动时(从onStartCommand(Intent, int, int)
返回后)被onStartCommand(Intent, int, int)
,那么它将计划重新启动,并且最后一次传送的Intent通过onStartCommand(Intent, int, int)
再次重新传递给它。 此意图将保持计划重新发送,直至服务呼叫stopSelf(int)
,并将起始ID提供给onStartCommand(Intent, int, int)
。 该服务将不会收到带有null Intent的onStartCommand(Intent, int, int)
调用,因为只有在处理完发送给它的所有Intents(并且任何此类未决事件将在重新启动时交付)后,它才会重新启动。
常量值:3(0x00000003)
int START_STICKY
从onStartCommand(Intent, int, int)
返回的onStartCommand(Intent, int, int)
:如果此服务的进程在启动时(从onStartCommand(Intent, int, int)
返回后)被onStartCommand(Intent, int, int)
,则将其保留在启动状态,但不保留此传递的意图。 稍后系统将尝试重新创建该服务。 由于它处于启动状态,因此保证在创建新服务实例后调用onStartCommand(Intent, int, int)
; 如果没有任何挂起的启动命令要传递给服务,它将被调用一个空意图对象,所以你必须小心检查这一点。
这种模式对于明确启动和停止运行任意时间段的内容很有意义,例如执行背景音乐播放的服务。
常数值:1(0x00000001)
int START_STICKY_COMPATIBILITY
恒从返回 onStartCommand(Intent, int, int)
:兼容性版本 START_STICKY
不保证 onStartCommand(Intent, int, int)
将被杀死之后再次调用。
常量值:0(0x00000000)
int STOP_FOREGROUND_DETACH
标记为stopForeground(int)
:如果设置,先前提供给startForeground(int, Notification)
的通知将从服务中分离。 只有当STOP_FOREGROUND_REMOVE
没有设置时才STOP_FOREGROUND_REMOVE
- 在这种情况下,通知将保持显示,但完全脱离服务,因此除了通过直接调用通知管理器之外不再进行更改。
常量值:2(0x00000002)
int STOP_FOREGROUND_REMOVE
标记为stopForeground(int)
:如果设置,先前提供给startForeground(int, Notification)
的通知将被删除。 否则,它将保持到稍后的通话( startForeground(int, Notification)
或stopForeground(int)
将其删除,或者服务被破坏。
常数值:1(0x00000001)
IBinder onBind (Intent intent)
将通信信道返回给服务。 如果客户端无法绑定到服务,可能会返回null。 返回IBinder
通常是一个复杂的界面已经described using aidl 。
请注意,与其他应用程序组件不同,此处返回的IBinder接口调用可能不会发生在进程的主线程上 。 有关主线程的更多信息可以在Processes and Threads中找到。
Parameters | |
---|---|
intent |
Intent : The Intent that was used to bind to this service, as given to Context.bindService . Note that any extras that were included with the Intent at that point will not be seen here. |
Returns | |
---|---|
IBinder |
Return an IBinder through which clients can call on to the service. |
void onConfigurationChanged (Configuration newConfig)
设备配置在组件运行时发生更改时由系统调用。 请注意,与活动不同,当配置更改时,其他组件不会重新启动:它们必须始终处理更改的结果,例如通过重新获取资源。
在调用此函数时,您的Resources对象将被更新为返回与新配置相匹配的资源值。
有关更多信息,请阅读 Handling Runtime Changes 。
Parameters | |
---|---|
newConfig |
Configuration : The new device configuration. |
void onDestroy ()
由系统调用以通知服务它已不再使用并正在被删除。 这个服务应该清理它所拥有的任何资源(线程,注册接收者等)。 返回后,将不会有更多的调用这个服务对象,它实际上已经死了。 不要直接调用这个方法。
void onLowMemory ()
这在整个系统内存不足时调用,并且主动运行的进程应该修剪内存使用情况。 虽然没有定义它的确切位置,但通常会在所有后台进程都被终止时发生。 也就是说,在达到托管服务和前台UI的杀死进程之前,我们希望避免杀死。
你应该实现这个方法来释放你可能持有的任何缓存或其他不必要的资源。 系统将从此方法返回后为您执行垃圾回收。
优选地,您应该从ComponentCallbacks2
实现onTrimMemory(int)
,以根据各种内存需求逐步卸载资源。 该API可用于API级别14和更高的,所以你应该只使用这个onLowMemory()
方法,旧版本的回退,可以治疗一样onTrimMemory(int)
与TRIM_MEMORY_COMPLETE
水平。
void onRebind (Intent intent)
当新的客户端连接到服务时调用,之前它已被通知所有已断开其onUnbind(Intent)
。 只有当onUnbind(Intent)
的实现被覆盖返回true时才会调用它。
Parameters | |
---|---|
intent |
Intent : The Intent that was used to bind to this service, as given to Context.bindService . Note that any extras that were included with the Intent at that point will not be seen here. |
void onStart (Intent intent, int startId)
此方法在API级别5中已被弃用。
改为实施onStartCommand(Intent, int, int)
。
Parameters | |
---|---|
intent |
Intent
|
startId |
int
|
int onStartCommand (Intent intent, int flags, int startId)
每当客户端通过调用startService(Intent)
显式启动服务时,由系统调用,提供它提供的参数和代表启动请求的唯一整数标记。 不要直接调用这个方法。
为了向后兼容,默认实现调用 onStart(Intent, int)
并返回 START_STICKY
或 START_STICKY_COMPATIBILITY
。
如果您需要在API级别5之前的平台版本上运行您的应用程序,则可以使用以下模型来处理较旧的onStart(Intent, int)
回调。 handleCommand
方法由您酌情执行:
// This is the old onStart method that will be called on the pre-2.0 // platform. On 2.0 or later we override onStartCommand() so this // method will not be called. @Override public void onStart(Intent intent, int startId) { handleCommand(intent); } @Override public int onStartCommand(Intent intent, int flags, int startId) { handleCommand(intent); // We want this service to continue running until it is explicitly // stopped, so return sticky. return START_STICKY; }
请注意,系统会在您的服务的主线程上调用它。 服务的主线程与在同一进程中运行的活动发生UI操作的线程相同。 你应该总是避免拖延主线程的事件循环。 在进行长时间运行的操作,网络调用或繁重的磁盘I / O时,您应该启动一个新线程,或使用AsyncTask
。
Parameters | |
---|---|
intent |
Intent : The Intent supplied to startService(Intent) , as given. This may be null if the service is being restarted after its process has gone away, and it had previously returned anything except START_STICKY_COMPATIBILITY . |
flags |
int : Additional data about this start request. Currently either 0, START_FLAG_REDELIVERY , or START_FLAG_RETRY . |
startId |
int : A unique integer representing this specific request to start. Use with stopSelfResult(int) . |
Returns | |
---|---|
int |
The return value indicates what semantics the system should use for the service's current started state. It may be one of the constants associated with the START_CONTINUATION_MASK bits. |
也可以看看:
void onTaskRemoved (Intent rootIntent)
如果服务当前正在运行并且用户已经删除了来自服务应用程序的任务,则会调用该服务。 如果您设置了ServiceInfo.FLAG_STOP_WITH_TASK
那么您将不会收到此回调; 相反,服务将被简单地停止。
Parameters | |
---|---|
rootIntent |
Intent : The original root Intent that was used to launch the task that is being removed. |
void onTrimMemory (int level)
当操作系统确定进程从其进程中删除不需要的内存是一个好时机时调用。 例如,当它进入后台并且没有足够的内存来保持尽可能多的后台进程运行时,会发生这种情况。 您不应该与级别的确切值进行比较,因为可能会添加新的中间值 - 如果值大于或等于您感兴趣的级别,通常需要比较。
要在任何点检索处理当前的修剪水平,可以使用 ActivityManager.getMyMemoryState(RunningAppProcessInfo)
。
Parameters | |
---|---|
level |
int : The context of the trim, giving a hint of the amount of trimming the application may like to perform. May be TRIM_MEMORY_COMPLETE , TRIM_MEMORY_MODERATE , TRIM_MEMORY_BACKGROUND , TRIM_MEMORY_UI_HIDDEN , TRIM_MEMORY_RUNNING_CRITICAL , TRIM_MEMORY_RUNNING_LOW , or TRIM_MEMORY_RUNNING_MODERATE . |
boolean onUnbind (Intent intent)
当所有客户端与服务发布的特定接口断开连接时调用。 默认实现什么也不做,并返回false。
Parameters | |
---|---|
intent |
Intent : The Intent that was used to bind to this service, as given to Context.bindService . Note that any extras that were included with the Intent at that point will not be seen here. |
Returns | |
---|---|
boolean |
Return true if you would like to have the service's onRebind(Intent) method later called when new clients bind to it. |
void startForeground (int id, Notification notification)
使该服务在前台运行,提供正在进行的通知,以便在此状态下向用户显示。 默认情况下服务是后台服务,这意味着如果系统需要杀死它们以回收更多内存(例如在Web浏览器中显示大页面),则可以杀死它们而不会造成太大的伤害。 您可以设置此标志,如果杀死您的服务会对用户造成干扰,例如您的服务正在执行背景音乐播放,则用户会注意他们的音乐是否停止播放。
如果您需要应用程序在API级别5之前的平台版本上运行,则可以使用以下模型根据需要调用旧的setForeground()或此现代方法:
private static final Class<?>[] mSetForegroundSignature = new Class[] { boolean.class}; private static final Class<?>[] mStartForegroundSignature = new Class[] { int.class, Notification.class}; private static final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class}; private NotificationManager mNM; private Method mSetForeground; private Method mStartForeground; private Method mStopForeground; private Object[] mSetForegroundArgs = new Object[1]; private Object[] mStartForegroundArgs = new Object[2]; private Object[] mStopForegroundArgs = new Object[1]; void invokeMethod(Method method, Object[] args) { try { method.invoke(this, args); } catch (InvocationTargetException e) { // Should not happen. Log.w("ApiDemos", "Unable to invoke method", e); } catch (IllegalAccessException e) { // Should not happen. Log.w("ApiDemos", "Unable to invoke method", e); } } /** * This is a wrapper around the new startForeground method, using the older * APIs if it is not available. */ void startForegroundCompat(int id, Notification notification) { // If we have the new startForeground API, then use it. if (mStartForeground != null) { mStartForegroundArgs[0] = Integer.valueOf(id); mStartForegroundArgs[1] = notification; invokeMethod(mStartForeground, mStartForegroundArgs); return; } // Fall back on the old API. mSetForegroundArgs[0] = Boolean.TRUE; invokeMethod(mSetForeground, mSetForegroundArgs); mNM.notify(id, notification); } /** * This is a wrapper around the new stopForeground method, using the older * APIs if it is not available. */ void stopForegroundCompat(int id) { // If we have the new stopForeground API, then use it. if (mStopForeground != null) { mStopForegroundArgs[0] = Boolean.TRUE; invokeMethod(mStopForeground, mStopForegroundArgs); return; } // Fall back on the old API. Note to cancel BEFORE changing the // foreground state, since we could be killed at that point. mNM.cancel(id); mSetForegroundArgs[0] = Boolean.FALSE; invokeMethod(mSetForeground, mSetForegroundArgs); } @Override public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); try { mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature); mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); return; } catch (NoSuchMethodException e) { // Running on an older platform. mStartForeground = mStopForeground = null; } try { mSetForeground = getClass().getMethod("setForeground", mSetForegroundSignature); } catch (NoSuchMethodException e) { throw new IllegalStateException( "OS doesn't have Service.startForeground OR Service.setForeground!"); } } @Override public void onDestroy() { handleDestroy(); // Make sure our notification is gone. stopForegroundCompat(R.string.foreground_service_started); }
Parameters | |
---|---|
id |
int : The identifier for this notification as per NotificationManager.notify(int, Notification) ; must not be 0. |
notification |
Notification : The Notification to be displayed. |
也可以看看:
void stopForeground (int flags)
从前台状态中删除此服务,如果需要更多内存,则允许它被终止。
Parameters | |
---|---|
flags |
int : Additional behavior options: STOP_FOREGROUND_REMOVE , STOP_FOREGROUND_DETACH . |
void stopForeground (boolean removeNotification)
同义词为 stopForeground(int)
。
Parameters | |
---|---|
removeNotification |
boolean : If true, the STOP_FOREGROUND_REMOVE flag will be supplied. |
void stopSelf ()
停止服务,如果它以前开始。 这与为此特定服务调用stopService(Intent)
相同。
也可以看看:
void stopSelf (int startId)
旧版本的 stopSelfResult(int)
不返回结果。
Parameters | |
---|---|
startId |
int
|
也可以看看:
boolean stopSelfResult (int startId)
如果最近一次启动的时间是startId,请停止服务。 这与针对此特定服务调用stopService(Intent)
的方法相同,但如果客户端有onStart(Intent, int)
尚未见过的开始请求,则可以安全地避免停止。
请小心您的电话订购此功能。 。 如果您使用最近收到的ID调用此函数,然后再为之前收到的ID调用此函数,则服务将立即停止。 如果您最终可能不按顺序处理ID(例如通过在不同的线程上分派它们),那么您有责任按照您收到的顺序来停止它们。
Parameters | |
---|---|
startId |
int : The most recent start identifier received in onStart(Intent, int) . |
Returns | |
---|---|
boolean |
Returns true if the startId matches the last start request and the service will be stopped, else false. |
也可以看看:
void dump (FileDescriptor fd, PrintWriter writer, String[] args)
将服务的状态打印到给定的流中。 如果您运行“adb shell dumpsys activity service <yourservicename>”(注意,要使此命令生效,服务必须正在运行,并且您必须指定完全限定的服务名称),则会调用此命令。 这与“dumpsys <servicename>”不同,后者仅适用于命名系统服务,并且在使用ServiceManager注册的IBinder
接口上调用dump(FileDescriptor, String[])
方法。
Parameters | |
---|---|
fd |
FileDescriptor : The raw file descriptor that the dump is being sent to. |
writer |
PrintWriter : The PrintWriter to which you should dump your state. This will be closed for you after you return. |
args |
String : additional arguments to the dump request. |