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>
...
<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);
}
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();
}
}
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(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)
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
publicvoid
// The service is being created
}
@Override
publicint
// The service is starting, due to a call to
returnmStartMode;
}
@Override
publicIBinder
// A client is binding to the service with
returnmBinder;
}
@Override
publicboolean
// All clients have unbound with
returnmAllowRebind;
}
@Override
publicvoid
// A client is binding to the service with
// after onUnbind() has already been called
}
@Override
publicvoid
// The service is no longer used and is being destroyed
}
}
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
publicvoid
onCreate
(){// The service is being created
}
@Override
publicint
onStartCommand
(Intent intent,int flags,int startId){// The service is starting, due to a call to
startService()
returnmStartMode;
}
@Override
publicIBinder
onBind
(Intent intent){// A client is binding to the service with
bindService()
returnmBinder;
}
@Override
publicboolean
onUnbind
(Intent intent){// All clients have unbound with
unbindService()
returnmAllowRebind;
}
@Override
publicvoid
onRebind
(Intent intent){// A client is binding to the service with
bindService()
,// after onUnbind() has already been called
}
@Override
publicvoid
onDestroy
(){// The service is no longer used and is being destroyed
}
}
Note:不像Activity的回调方法,你不需要调用父类的实现。
Note: 当一个startService call stopSelf() or stopService() 被停止后,它并没有一个类似于onStrop()的回调函数,
所以,除非service绑定了一个客户端,当它停止,系统销毁时---onDestroy() 是唯一的回调函数。
- Service
- Service
- service
- Service
- service
- Service
- Service
- service
- Service
- Service
- Service
- service
- service
- Service
- Service
- Service
- Service
- Service
- Silverlight在win2003部署IIS时WCF无法显示页面.txt
- 身体这些部位不舒服的时候,你知道意味着什么吗?
- PLSQL 9 注册码
- java和oracle简单的日期格式化
- Jquery 例外被抛出且未被接住
- Service
- iOS开发ASIHttpRequest创建和执行request
- wordpress中do_action方法,及其作用
- Silverlight中WCF定义的类,在客户端不能发现的问题
- Linux chkconfig命令
- opcv学习日志 7 光照
- Xdebug安装与使用
- poj 1837 Balance 01背包
- Bound Service