Service

来源:互联网 发布:华云数据服务有限公司 编辑:程序博客网 时间:2024/04/30 08:52

from android develop API Guides

Services

service 是anroid 的一个组件,它能在后台长时间的运行,是没有UI的。
别的组件能 start a service,当用户切换到别的应用时,它也能在后台继续运行。
此外,组件也能bind to a service 与它交互,甚至能执行进程间通信。(interprocess communication IPC)
如:service 可以在后台处理网络传输,播放音乐,处理文件 I/O,与content provider交互。
 
service 有两种实现:
 
Started
        service 可以通过组件(such as an activity)调用 startService() 启动。
        一旦启动,service会在后台一直运行,甚至启动它的组件销毁了。
        通常,启动一个service来处理一个单一的操作,并不会返回结果给调用者。
        如:可能通过网络下载,上传文件,处理完后,他应该停止自己。
 
Bound
        service 可以通过组件调用 bindService() 进行绑定。
        bind service 提供 client-server 借口,允许组件与它交互,发送请求,取得结果,甚至进行IPC通信。
        bind service 的生命周期与绑定它的组件的生命周期一致,多个组件可以绑定到一个service上,当它们都unbound时,service才会销毁掉。
 
started 和 bound可以同时使用,实现回调方法,onStartCommand() for started, onBind() for binding。
不管使用哪种,应用组件都能使用它,甚至是在不同的应用,就像Activity使用Intent一样。
也可以在 manifest file 指定不被别的应用访问。
 
Caution:service 是运行在 hosting process(宿主进程)的main thread上。它不会自己开个线程,或运行在别的进程上(除非你指定)。
也就是说,在service中,你应该开个线程去处理繁重的工作,以免阻塞UI。
 

The Basics

先说说主要的回调方法
 
onStartCommand()
    组件startService(),系统就会调用此方法,一旦开启,它就会在后台一直运行,如果实现了这方法,
    所以当service完成工作时,你可以停止它,stopSelf(), stopService().
    (如果你想提供binding,则不需要实现这方法。)
 
onBind()
    组件调用bindService,系统 就会调用此方法。
    如果你实现了这方法,你必须通过返回一个 IBinder 来为客户端提供一个接口来与service通信。
    通常总应该实现这方法,如不允许binding,则返回null。
 
onCreate()
    service第一次创建时,系统会调用此方法,执行一次性的建立过程。(之前,要么调用onStartCommand() or onBind())
    如果service已经在运行了,这方法不会被调用。
 
onDestroy()
    service 不在使用或销毁时,系统会调用此方法。
    这是service最后调用的地方,你可以清理一些资源,如threads,registered listeners,receivers,etc。
 
当内存较少时,系统会强行停止你的service来恢复一些资源,如果service时绑定到前台的activity上时,通常不太会killed掉。
如果service定义为 run in the foregound , 那永远不会被killed掉。
如果service是长时间运行的那种(通过startService),随着时间的推移,系统会把它放到后台任务列表较低的位置上,这会容易被系统
kill掉,所以如果你的service时started的,你必须把它设计为可比被系统重新启动的。这取决于你在 onStartCommand() 返回的值。
 
接下来讲讲具体过程,使用。
 

Declaring a service in the manifest

简单的
<manifest ...>
  ...
 
<application ...>
     
<serviceandroid:name=".ExampleService"/>
      ...
 
</application>
</manifest>
 
也可以通过intent filters定义你的service,这样的话,你设备上任何应用的组件都能通过startService()和匹配的intent来启动它。
如果不想别的应用使用到你的service,你不要提供任何intent filters了。只能明确通过指定名字启动它。
此外,android:exported="false",确保你的service时私有的,即使你使用了intent filters。
 

Creating a Started Service


举个例子,有个activity要把数据保存到online database上。
activity可以启动个service,通过intent把数据传给startService()。service会在onStartcommand()接收这个intent,
然后连接网络,进行数据转移,完成后,应停止服务,销毁它。
 
Caution:通常默认的,service是运行应用的同一进程中的主UI上的,所以可能会block UI,你应该在service中开个线程。
 
通常,有两个class可被extends来启动服务:
 
Service
   This is the base class for all services. 如果extend这个class,最主要的是开启个线程去处理服务的工作。
       
IntentService
    这是service的一个子类,使用一个工作线程每次一个的处理所有的请求。
    你不必要求你的service同时处理多个请求时,这是最好的选择了。
    你所要做的就是实现 onHandleIntent(),他能在后台处理每个intent的请求。
 
接下来使用了。
 

Extending the IntentService class

The IntentService does the following:
  • 创建一个默认的worker thread 来处理所有的传递给 onstartCommand()的intent,这个thread是与main thread分离的。
  • 创建一个工作队列每次把一个intent传给onHandleIntent(),所以你不用担心多线程的问题。
  • 在所有的请求处理完后,会停止服务,所以你不必调用stopSelf()。
  • 提供默认的onBind()实现,返回null。
  • 提供默认的onStartCommand()实现,它会发送intent到工作对列的,然后再把intent发送到onHandleIntent()实现。
所有的加起来,其实你只需要实现啊 onHandleIntent()。(可能还要有个为service提供个简单的构造函数)
 
举个列子:
publicclassHelloIntentServiceextendsIntentService{

 
/**
   * A constructor is required, and must call the super
IntentService(String)

   * constructor with a name for the worker thread.
   */

 
publicHelloIntentService(){
     
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.
   */

 
@Override
 
protectedvoid 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()。
 
如果要override别的回调,如onCreate(), onStartCommand(), or onDestroy,记得要call super 的实现,这样IntentService
才能handle到worker thread 的生命周期。
如,onStartCommand() 必须返回默认实现(为了把intent传递到onHandleIntent())。
@Override
publicint onStartCommand(Intent intent,int flags,int startId){
   
Toast.makeText(this,"service starting",Toast.LENGTH_SHORT).show();
   
returnsuper.onStartCommand(intent,flags,startId);
}
除了onHandleIntent(),只有一个不需要call super class的,就是onBind()。
 
下节会介绍extends Service,可能有点复杂,但如果你要同时处理请求时,这个比较适合。
 
 

Extending the Service class

处理多线程要用到这种形式。而IntentService 是每次处理一个请求。
 
publicclassHelloServiceextendsService{
 
privateLooper mServiceLooper;
 
privateServiceHandler mServiceHandler;

 
// Handler that receives messages from the thread
 
privatefinalclassServiceHandlerextendsHandler{
     
publicServiceHandler(Looper looper){
         
super(looper);
     
}
     
@Override
     
publicvoid 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 job
          stopSelf
(msg.arg1);
     
}
 
}

 
@Override
 
publicvoid 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=newHandlerThread("ServiceStartArguments",
           
Process.THREAD_PRIORITY_BACKGROUND);
    thread
.start();
   
   
// Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper
= thread.getLooper();
    mServiceHandler
=newServiceHandler(mServiceLooper);
 
}

 
@Override
 
publicint 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 job
     
Message msg= mServiceHandler.obtainMessage();
      msg
.arg1= startId;
      mServiceHandler
.sendMessage(msg);
     
     
// If we get killed, after returning from here, restart
     
return START_STICKY;
 
}

 
@Override
 
publicIBinder onBind(Intent intent){
     
// We don't provide binding, so return null
     
returnnull;
 
}
 
 
@Override
 
publicvoid onDestroy(){
   
Toast.makeText(this,"service done",Toast.LENGTH_SHORT).show();
 
}
}
 
onStartCommand() 返回的是一个integer,这个值描述了在系统kill掉service后,系统如何继续处理service的。
 
START_NOT_STICKY
    在onStartCommand()返回后,如果系统kill掉service,do not recreate the service,除非有pending intents 传递过来。
    可以避免运行不必要的service,或避免当你的应用restart时继续没完成的工作。
 
START_STICKY
    在onStartCommand()返回后,如果系统kill掉service,会recreate the service and call onStartCommand()。但是不会重新传递最后的intent。
    反而calls onstartCommand() with a null intent,除非有pending intents启动服务。
    这种情形适用于 media players(或类似的服务),它们不执行命令,而是一直在运行或等待一个任务。
 
START_REDELIVER_INTENT
    在onStartCommand()返回后,如果系统kill掉service,会recreate theservice and call onStartCommand() with the last intent。
      这种情形适用于那些正在活跃的处理任务时,需要马上resumed的服务,如downloading a file。
 
 

Starting a Service

Intent intent=newIntent(this,HelloService.class);
startService
(intent);
startService() 一返回,系统就会调用onStartCommand(),如果service第一次运行,calls onCreate() then call onStartCommand()。
 
如果service没提供绑定,那么传递 intent 就是service和组件之间的唯一通信方式。
但如果想service发送个结果回来,则可以为客户端创建一个pendingIntent for a broadcast(with getBroadcast()),
service能通过broadcast传递结果。
 
多个请求启动服务,相应的会有多个onStartCommand()的调用。但只有一个请求能停止服务(stopSelf() or stopService())
 

Stopping a service

在service在onStartCommand中同时处理多个请求时,你不能简单的在一个请求处理完后停止服务,这会导致后来的请求也无效,因为service被停止了。
可以指定ID 给 stopSelf(int),到指定哪个请求被停止了,而在新的请求到来时,调用了stopSelf(int),由于ID不匹配,它的service就不会停止掉。
 

Creating a Bound Service


先简单介绍一下 bound service,会开另一篇详细讲解它。
 
组件通过bindService()来绑定服务,建立个长期连接。
建立一个bound service,activities,或者应用中别的组件可以与之交互。或者是提供你应用的一些功能给别的应用使用(通过IPC)。
 
要建立一个bound service,需要实现 onBind(),它会返回一个能与service进行通信的IBinder接口。
别的组件调用bindService()或的这个接口,就可以调用service的方法了。
bound service只为绑定它的组件服务,如果没有组件绑定它,系统就会销毁它。
 
多个clients能同时绑定到一个service上,当完成交互时,calls unbindService(), 系统就会销毁掉它。

Running a Service in the Foreground


前台服务 foreground service 时不会被系统kill的,它必须为状态栏提供一个通知。这个通知是不会消失的,除非在service停止或从foreground移除掉。
 
例如:音乐播放器从一个service播放音乐,应该被设置喂foreground,用户像明确知道他的操作,状态栏的通知,也应该显示当前播放的音乐。
 
call startForeground() 来设置。
Notification notification=newNotification(R.drawable.icon, getText(R.string.ticker_text),
       
System.currentTimeMillis());
Intent notificationIntent=newIntent(this,ExampleActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this,0, notificationIntent,0);
notification
.setLatestEventInfo(this, getText(R.string.notification_title),
        getText
(R.string.notification_message), pendingIntent);
startForeground
(ONGOING_NOTIFICATION_ID, notification)
 
要把service移除foreground,call stopForeground(boolean),参数是boolean,说明是否要从状态栏移除notification。这方法并不会停止service,当然,如果停止了正在运行的foreground 的service,通知自然被移除掉。
 
Caution: The integer ID you give to startForeground() must not be 0.
 

Managing the Lifecycle of a Service


service 的生命周期,有两种形式:
  • A started service
  • A bound service
两种形式并不是完全分离的,已经startService()的服务也可以进行绑定。

Implementing the lifecycle callbacks

publicclassExampleServiceextendsService{
   
int mStartMode;      // indicates how to behave if the service is killed
   
IBinder mBinder;      // interface for clients that bind
   
boolean mAllowRebind;// indicates whether onRebind should be used

   
@Override
   
publicvoidonCreate(){
       
// The service is being created
   
}
   
@Override
   
publicintonStartCommand(Intent intent,int flags,int startId){
       
// The service is starting, due to a call tostartService()
       
returnmStartMode;
   
}
   
@Override
   
publicIBinderonBind(Intent intent){
       
// A client is binding to the service withbindService()
       
returnmBinder;
   
}
   
@Override
   
publicbooleanonUnbind(Intent intent){
       
// All clients have unbound withunbindService()
       
returnmAllowRebind;
   
}
   
@Override
   
publicvoidonRebind(Intent intent){
       
// A client is binding to the service withbindService(),
       
// after onUnbind() has already been called
   
}
   
@Override
   
publicvoidonDestroy(){
       
// The service is no longer used and is being destroyed
   
}
}
 
 
Note:不像Activity的回调方法,你不需要调用父类的实现。
 
 
 
Note: 当一个startService call stopSelf() or stopService() 被停止后,它并没有一个类似于onStrop()的回调函数,
所以,除非service绑定了一个客户端,当它停止,系统销毁时---onDestroy() 是唯一的回调函数。
 
原创粉丝点击