这篇博文是我对Google Android开发官方文档Service这一模块的翻译,第一次写翻译有不好的地方尽情谅解,我也是尽自己可能保留英文原版的意思,只作翻译不加自己看法。
服务(Service)是一个可以长期运行在后台但是没有用户界面的应用组件。其他应用组件可以启动服务(Service),用户切换到其他应用还是可以运行。此外,组件可以绑定服务(Service)并且相互影响,并且可以进程间通信(IPC)。例如,网络可以执行网络通信,播放音乐,文件I/O, 和内容提供者的通信,以及所有在后台的活动。
服务从本质上分为两种:
start启动:
应用组件(例如:Activity)通过调用startService()方法来启动服务,服务就处于启动状态。一旦service在后台被起动,无论启动它的组件是否被摧毁都能长期运行。通常一个被启动的service执行一些简单的操作,并且不给调用者返回结果。例如,这个可以通过网络下载或上传文件。当这些操作结束,service会自己停止。
Bound绑定:
当一个应用组件通过调用bindService()绑定一个服务,这个服务就处于bound状态。一个被绑定的service会提供一个客户端-服务端的接口,这个提供组件和serice之间通信,包括发送请求,收到结果,以及进程间的通信。一个被绑定的service存活时间和绑定它的组件一样长。多个组件可以同时绑定一个service,只有当所有组件都解除绑定时,这个service才会被销毁。
尽管这个文档是分开来讨论这两种service的,但是你的service可以同时直接启动和被绑定,这取决于你是否实现这两个方法:onStartCommand()运行组件启动service,和onBind() 方法组件绑定service。
不管service是被启动的,被绑定的还是两者皆有。任何应用组件可以使用它(甚至是另外的应用)。相同的,任何应用组件可以通过Intent启动service。然而你可以在manifest文件里定义一个私有的service, 来阻止其他应用的访问。这个在“在manifest文件中定义service”这一章节中会重点讨论。
service是运行在主进程中的主线程,service不会创建自己的线程也不会运行在分进程中(除非自己指定)。这个意味着当你的service去做一些CPU消耗很大的工作时或者阻塞性的操作(后台MP3播放和网络通信),你需要在service中创建一个子线程来完成这些操作。通过使用子线程,你可以减少应用无响应(ANR)的问题,并且你的应用在Activities上专门用来用户交互。
创建一个service你必须创建一个类集成自Service类(或者Service类的子类)。在你的应用中,你需要重写一些关于Service生命周期和组件绑定service机制的关键方法,如果合适。需要重写的最重要的方法是:
onStartCommand()
当另外的组件例如Activities,调用startService()需要service启动,这个时候系统会调用onStartCommand()这个方法。一旦这个方法被启动,service就处于启动状态,并且会一直在后台运行。如果你实现了这个方法,在service工作完成后需要调用stopSelf()或者stopService(),来停止service(如果你只需要绑定这个service, 就不需要实现这个方法)
onBind()
另外的组件通过调用bindService()方法来绑定service(例如实现RPC),系统将会调用onBind()方法。在这个实现方法中,你要返回一个IBinder对象来做组件和service之间的通信。一般情况下都需要实现这个方法,如果你不需要绑定,在这个方法中你可以返回null。
onCreate()
服务在第一次被创建和执行一次性操作,系统将会调用onCreate()这个方法(在onStartCommand() 和onBind()两个方法之前调用),如果service, 已经在运行,这个方法就不会执行。
onDestroy()
当service不在被使用并且已经被销毁,系统将会调用onDestroy()这个方法。service需要实现这个方法来清理资源,例如子线程,注册的接口,注册的广播接收器等。这是service最后被调用的方法。
如果一个控件通过调用startService()来启动Service(将会调用onStartCommon()方法),这个Service将会一直运行直到它调用stopService()方法,或者其他控件调用stopService()来停止Service。
如果一个控件通过调用bindService()来创建Service(那么onStartCommon()不会被调用),这个Service将会一直运行知道控件解绑它。一旦这个Service被所有的控件解绑,这个Service将会被系统销毁。
Android系统将会关闭Service只有当内存低的时候,系统会把这些资源提供给有焦点的Activity。如果Service是被绑定在有焦点的Activity,这个Service被销毁的概率将会大大降低。如果Service被定义为运行在前台(run in the foreground这个之后讨论), 这个Service几乎不会被销毁。然而,如果一个Service被启动了并且已经长期运行,经过时间的推移,系统会降低它在后台任务列表中的优先级,这个Service将会很容易受影响被销毁掉。如果Service已经启动,你必须优雅地设计它通过系统来重启。如果系统销毁了Service, 在内存资源有可用的时候将会重新启动它。(当然这个还跟你在onStartCommon中返回的参数有关)。获取更多关于Service被系统销毁的信息,看Processes and Threading 这一章节。
在接下来的章节中,你将会看到不同的创建Service的方法,和在不同应用组件来使用Service。
跟Activity(或者是其他组件)一样,所有的Service你都必须定义在应用的l文件中。
定义你的Service,添加一个标签作为标签的子标签,例如:
<manifest ... >...<application ... ><service android:name=".ExampleService" />...</application>
</manifest>
看标签,来获取更多关于在配置文件中定义Service的信息。
还有很多标签可以包含在标签里面来定义各种参数,比如开启Service运行时需要的权限。android:name标签是唯一一个必须定义的标签,这个指出了这个Service的类名。一旦你发布了你的应用,你将不能改这个名字,因为如果你改了,有些Intent的启动或者绑定Service都依赖于这个,将有无法启动的风险。
为了确定APP是安全的,一般使用明确的Intent来启动或绑定Service,并且不要定义Intent的过滤器。这很重要,你允许一下模糊方法来启动Service,你可以提供一些过滤器给Service,从Intent中包含的名字。但是这样你必须使用setPackage()给Intent设置package,这个给那个Service提供了足够的信息来模糊启动。
此外,设置android:exported = “false”标签来确保你的Service只有在你的APP中使用,这样就有效的停止了其他APP来启动这个service,甚至是使用明确的Intent。
一个已经启动的Service是另外组件调用startService()启动的,会调用onStartCommon()方法。
当一个Service已经被启动,它有自己的生命周期,并且独立于启动它的组件,这个Service可以在后台无限的运行,就算启动它的组件已经被销毁。这个Service需要调用stopSelf()来自我销毁,当它的工作已经完成了,其他的组件也可以调用stopService()来停止Service。
一个应用组件像Activity调用startService()来启动Service,可以通过Intent来传递任何参数给Service使用。这个Service在onStartCommon()方法里面可以获取到Intent。
例如,一个Activity需要保存一些数据到线上的数据库。这个Activity可以启动一个关联的Service,并且通过startService()方法把数据传递但Service来保存。Service在onStartCommon()方法里面获取到Intent,连接网络来执行数据库事务。当事务完成的时候,Service会自我停止,然后销毁掉。
注意:默认情况下一个Service运行在应用的主线程所在的同一个进程中,如果你的Service表现加强或阻塞操作当用户在一个Activity中相互影响, Service会降低activity的性能。为了不影响应用性能,你应该在Service里面开启一个子线程。
一般的,有两个类可以供你来继承或者创建一个启动的Service:
Service:
这是所有Service的基类。当你继承这个类,你需要创建一个子线程,来做所有服务工作,因为Service运行在主线程。默认地,这样将会所有运行的Activity在这个应用中的性能。
IntentService:
这是一个Service类的子类,这个将会在工作线程来执行请求工作。这是最好的选择当你的Service不需要同时执行多个请求。你需要做的是要实现onHandlerIntent()方法,这里将会收到Intent来启动请求,这样你就可以在后台工作。
在接下来的章节中,将会讨论怎么来使用这些类。
因为大多数的已启动Service不需要去同时执行多种请求(这回变成危险的多线程方案),这个时候最好的方案就是使用IntentService类。
IntentService有以下特性:
所有这些必须要做的就是实现onHandlerIntent()方法,来做客户端提供的工作。(可是,你还需要提供Service构造方法)
下面是实现IntentService的案例:
public class HelloIntentService extends IntentService {/*** A constructor is required, and must call the super IntentService(String)* constructor with a name for the worker thread.*/public HelloIntentService() {super("HelloIntentService");}/*** The IntentService calls this method from the default worker thread with* the intent that started the service. When this method returns, IntentService* stops the service, as appropriate.*/@Overrideprotected void onHandleIntent(Intent intent) {// Normally we would do some work here, like download a file.// For our sample, we just sleep for 5 seconds.long endTime = System.currentTimeMillis() + 5*1000;while (System.currentTimeMillis() < endTime) {synchronized (this) {try {wait(endTime - System.currentTimeMillis());} catch (Exception e) {}}}}
}
你所需要做的就是一个构造方法和实现onHandleIntent()方法。
如果你决定去重写其他的回掉方法,例如onCreate(), onstartCommon(), onDestroy(), 确定调用了父类的方法。这样IntentService也许会这些生命周期在工作线程。
例如,onStartCommon()必须返回默认的实现方法(这里决定了onHandlerIntent()方法获取Intent传递)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();StartCommand(intent,flags,startId);
}
除了onHandleIntent()之外,唯一不需要调用父方法的是onBind()方法(但是只有当Service允许绑定的时候才去实现它)
在接下来章节中,你会看到很多Service实现,当继承基础Service类时。这会有很多代码,如果你需要同时处理多种请求。
跟你在之前章节看到的一样,使你使用IntentService来启动Service变得很简单。然而,你需要Service去执行多线程(代替工作队列来执行请求),这样你可以基础Service类来操作Intent。
比较,下面的例子代码是继承Service类,跟之前IntentService类的例子执行相同的工作。这个对于每个请求,它都用一个工作线程来执行请求。
public class HelloService extends Service {private Looper mServiceLooper;private ServiceHandler mServiceHandler;// Handler that receives messages from the threadprivate final class ServiceHandler extends Handler {public ServiceHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {// Normally we would do some work here, like download a file.// For our sample, we just sleep for 5 seconds.long endTime = System.currentTimeMillis() + 5*1000;while (System.currentTimeMillis() < endTime) {synchronized (this) {try {wait(endTime - System.currentTimeMillis());} catch (Exception e) {}}}// Stop the service using the startId, so that we don't stop// the service in the middle of handling another jobstopSelf(msg.arg1);}}@Overridepublic void onCreate() {// Start up the thread running the service. Note that we create a// separate thread because the service normally runs in the process's// main thread, which we don't want to block. We also make it// background priority so CPU-intensive work will not disrupt our UI.HandlerThread thread = new HandlerThread("ServiceStartArguments",Process.THREAD_PRIORITY_BACKGROUND);thread.start();// Get the HandlerThread's Looper and use it for our HandlermServiceLooper = Looper();mServiceHandler = new ServiceHandler(mServiceLooper);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();// For each start request, send a message to start a job and deliver the// start ID so we know which request we're stopping when we finish the jobMessage msg = mServiceHandler.obtainMessage();msg.arg1 = startId;mServiceHandler.sendMessage(msg);// If we get killed, after returning from here, restartreturn START_STICKY;}@Overridepublic IBinder onBind(Intent intent) {// We don't provide binding, so return nullreturn null;}@Overridepublic void onDestroy() {Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();}
}
跟你看到的一样,这个将会比IntentService做更多工作。
然而,因为你分别执行调用onStartCommon(),你可以同时执行多个请求。这不是这个例子做的,但是如果这是你需要的,你可以为每一请求创建一个新线程,而且立刻运行。(而不是等优先级高的请求结束)
发现onStartCommon()方法必须返回一个整型,这个整型描述了系统怎么继续或是销毁这些Service,这些返回值必须是下面几个中的一个:
你可以从一个Activity或其他组件,调用startService()方法传递Intent参数来启动。Android会调用onStartCommon()方法,并且传递Intent参数进去(你从来不要直接调用onStartCommon()方法)。
例如,一个activity可以使用明确的Intent和startService(),就像之前提到的一样。
Intent intent = new Intent(this, HelloService.class);
startService(intent);
startService() 方法将会立即返回,Android系统会调用Service的onStartCommon()方法。如果这个Service还没有在运行,系统将会调用onCreate()方法,然后调用onStartCommon()。
如果service也没提供绑定,Intent通过startService()分发是唯一一个方法和启动控件之间的通信。然而,如果你需要Service返回一个结果。你可以使用PendingIntent给broadcast来传递到Service启动。Service可以使用广播来分发结果。
多种请求来启动Service,将会调用onStartCommon()得到多种响应。然而只需要一个请求来停止Service(调用stopSelf()或者stopSevice())。
一个已经启动的Service需要自己管理生命周期。系统不会停止或注销Service除非它需要回收系统内存并且Service在调用onStartCommon()后开始运行。所以Service需要通过调用stopSelf()方法或者其他组件调用stopService()来停止它。一旦调用stopSelf()或者stopService()方法来停止,系统会尽快销毁Service。
然而如果你的Service同时在onStartCommon执行了多种请求,这样的当你执行完一个请求后不会销毁Service,因为这个时候可能刚刚收到一个新请求。为了避免这样的问题,你可以使用stopSelf(int)来确保你请求停止Service是基于最近的一个请求。当你调用stopSelf(int)的时候传递一个启动请求时的ID,来确保关闭的是最近一个请求。如果在你调用stopSelf(int)的时候有收到了一个新的请求,这样ID将会不匹配,也就不会停止Service。
注意:当Service工作完成的时候需要关闭自己,这很重要,可以避免浪费系统资源和电量。如果需要的话,其他组件可以通过调用stopService()来停止。甚至你是绑定这个Service的,也需要停止Service。
查看更多关于Service的生命周期,来看接下来 管理Service生命周期这一章节。
一个绑定的Service允许应用组件调用bindService(),来创建一个长期连接(一般情况下,不允许组件调用startService()来启动Service)。
你需要创建一个绑定的Service,当你需要它和其他activity交互,或者通过IPC把应用的某些功能开放出来。
创建一个绑定的Service,你必须实现onBind()这个回掉方法来返回一个IBinder对象用作和Service之间的交互。其他应用组件可以调用bindService()来恢复那个接口,并且调用Service上面的方法。这个Service是为了服务绑定它的其他应用组件,所以当没有应用组件绑定它时,系统将会销毁它(你不需要停止一个绑定的Service)。
创建一个绑定的Service,最先要做的就是定义一个接口来指明什么样的组件可以跟这个Service有联系。这个组件跟Service之间联系的接口必须实现IBinder,并且这在你Service中onBind()中是必须返回的。一旦组件收到IBinder对象,它可以和Service通过这个接口来交互。
多个组件可以同时绑定一个Service,当组件和Service之间的交互结束时,需要调用unBindService()来解绑。一旦没有任何组件绑定这个Service,系统将会销毁这个Service。
这有很多种方法来实现绑定Service,并且这比开启一个Service复杂地多。所以绑定一个Service,将会在一个独立的章节讨论。
一旦运行Service,它可以使用Toast Notification和Status Bar Notifications来通知用户。一个Toast Notification是把消息显示在当前窗口,显示一段时间然后消失。然而,Status Bar Notifications是在Status Bar显示一个图标和消息。可以设置一个点击的动作(比如开始一个activity)。
通常,在后台工作完成后Status Bar Notifications是最好的方法来提醒(比如一个文件下载完毕),而且用户可以立即来操作这个。当用户通过扩展view点击这个通知,这个通知可以打开一个activity(比如去查看下载文件)
一个前台运行的Service,可以被认为是用户可以活跃的,并且在内存低的时候不会考虑被销毁。一个前台Service必须提供一个Status Bar Notifications, 并被定义为“Ongoing”。这意味着这个通知将不会消失,除非这个Service被销毁或者不在前台显示。
例如,音乐播放器从Service播放音乐,需要被定义为前台运行。因为用户会明确去操作它。这个通知指出了当前播放的音乐,并且允许用户打开一个activity。
可以调用startForeground(),来开启一个前台运行Service。这个方法需要两个参数,一个integer类型的参数表示Notifications的类型。类如:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = Activity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(ification_title),getText(ification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
注意:传给startForeground()方法的integer类型的ID不能为0.
调用stopForeground(),来把Service从前台移除。这个方法需要传一个boolean参数,表示是否把Status Bar Notifications也移除。这个方法不会停止Service,然而如果当这个Service还在前台运行时你停止它,那通知也会被移除。
Service的生命周期比Activity的简单得多。然而在创建和销毁它的时候更加需要注意,因为它可以在用户不注意的情况下在后台运行。
Service的生命周期,它的创建和销毁可以分为两种:
这两种方法也不是完全分开的,你也可以绑定一个通过startService()方法启动的Service。例如,一个后台运行的音乐播放Service可以通过startService()来启动播放,之后用户希望操作这个播放器或者获取一些关于这个音乐的信息,可以调用bindService()将它和activity绑定。在这种情况下,调用stopService()或是stopSelf()都不能停止Service,直到所有组件都解绑后才会被销毁。
就像activity,Service的生命周期也有回调方法,你可以在适当的时候去回调它。下面是几种Service的回掉方法。
public class ExampleService extends Service {int mStartMode; // indicates how to behave if the service is killedIBinder mBinder; // interface for clients that bindboolean mAllowRebind; // indicates whether onRebind should be used@Overridepublic void onCreate() {// The service is being created}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// The service is starting, due to a call to startService()return mStartMode;}@Overridepublic IBinder onBind(Intent intent) {// A client is binding to the service with bindService()return mBinder;}@Overridepublic boolean onUnbind(Intent intent) {// All clients have unbound with unbindService()return mAllowRebind;}@Overridepublic void onRebind(Intent intent) {// A client is binding to the service with bindService(),// after onUnbind() has already been called}@Overridepublic void onDestroy() {// The service is no longer used and is being destroyed}
}
通告:跟activity的什么周期不一样,重写这些回调方法不是必须调用父方法。
Service的生命周期
通过实现这些方法,你可以管理Service生命周期。
小贴士:不管启动的Service是通过stopSelf()或者stopService()结束的,他们都没各自的回调,除非是绑定的,不然Service被系统销毁的时候都只能收到onDestroy()一个回调。
上面那个图阐述了Service典型的回调方法,尽管上图中将两种启动方法区分开来了,但是无论是哪种方法启动的,其他组件都可以来绑定它。所以,Service可以在onStartCommon()进行初始化(组件调用startService()方法),然后也可以继续有onBind()回调(当组件调用bindService()方法)。
以上就是对Google对Android开发官方文档Service这一模块的翻译,第一次写翻译有不好的地方尽情谅解,我也是尽自己可能保留英文原版的意思,只作翻译不加自己看法。
本文发布于:2024-02-05 06:14:59,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170726007863743.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |