Android创建服务之startedservice详细介绍
创建startedservice
应用组件(例如Activity)调用startService()来启动一个Service,将需要的参数通过Intent传给Service,Service将会在onStartCommand函数中获得Intent。
有两种方式可以创建startedservice,一种是扩展Service类,另外一种是扩展IntentService类
扩展Service
这是所有服务的基类。扩展这个类的时候,特别重要的一点是,需要创建一个新的线程来做服务任务,因为service默认是运行在你的主线程(UI线程)中的,它会使你的主线程运行缓慢。
扩展IntentService
这是一个service的子类,他可以在一个工作线程中处理所有的启动请求。如果你不需要同一时刻出来所有的服务请求,使用IntentService是一个很好的选择。你需要做的仅仅是实现onHandlerIntent()方法,通过这个函数处理接受的每一个启动请求。
下面我们学习如何扩展IntentService类和Service类
扩展IntentService类
IntentService做了什么?
1.创建一个独立于主线程的工作线程,用于执行通过onStartCommand()传来的所有的intent。
2.创建一个工作队列,将接受的所有intent一个一个的传给onHandlerIntent(),所以同一时间内你只处理一个intent,不用担心多线程的问题。
3.当所有的请求都处理完后,停止服务,所以你不需要手动调用stopSelf()。
4.提供onBind()函数的默认实现,返回null
5.提供onStartCommand()函数的默认实现,它把intent发送到工作队列中去,然后工作队列再发送到你的onHandlerIntent()函数中。
有了上面的基础,你仅仅要做的就是实现onHandlerIntent()。并且实现一个小小的构造函数。
参考下面的例子:
publicclassHelloIntentServiceextendsIntentService{
/**
*Aconstructorisrequired,andmustcallthesuperIntentService(String)
*constructorwithanamefortheworkerthread.
*/
publicHelloIntentService(){
super("HelloIntentService");
}
/**
*TheIntentServicecallsthismethodfromthedefaultworkerthreadwith
*theintentthatstartedtheservice.Whenthismethodreturns,IntentService
*stopstheservice,asappropriate.
*/
@Override
protectedvoidonHandleIntent(Intentintent){
//Normallywewoulddosomeworkhere,likedownloadafile.
//Foroursample,wejustsleepfor5seconds.
longendTime=System.currentTimeMillis()+5*1000;
while(System.currentTimeMillis()<endTime){
synchronized(this){
try{
wait(endTime-System.currentTimeMillis());
}catch(Exceptione){
}
}
}
}
}
如果你要实现其他的回调函数,例如onCreate,onStartCommand,onDestroy一定记得调用父类相应的函数,这样IntentService才能正确的处理工作线程。
例如,你需要在onStartCommand函数中弹出一个提示,那么你可以这样写:
@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
Toast.makeText(this,"servicestarting",Toast.LENGTH_SHORT).show();
returnsuper.onStartCommand(intent,flags,startId);
}
有一点例外的是,如果你需要其他组件绑定服务,那么你的onBind函数不需要调用父类的onBind。
在下一节中,你将会看到通过扩展service类来实现与本节相同的服务,所不同的是代码会更多,但是同样意味着更灵活,特别是你需要同时处理多个请求时,比较适合直接扩展Service。
扩展Service类
如同你在上一节看到的一样,使用IntentService来实现一个startedservice非常简单。如果你需要你的service来执行多个线程,那么你需要扩展Service类去处理每个intent。
作为对比,下面的例子用Service类实现了和上一节中一样功能的服务。
//Handlerthatreceivesmessagesfromthethread @Override //GettheHandlerThread"sLooperanduseitforourHandler @Override //Foreachstartrequest,sendamessagetostartajobanddeliverthe //Ifwegetkilled,afterreturningfromhere,restart @Override @Override 如同你看到的,比IntentService的例子多了好多代码。 因为你自己处理每次的onStartcommand(),所以你可以在同一时间处理多个请求。这个例子没有这样做,但是如果你愿意,你完全可以每收到一个请求的时候,创建一个新线程并且立即运行,而不是等到上一个请求处理完成后再运行。 注意,onStartCommand()函数必须返回一个整数。这个整数描述了当系统杀死该服务时将要如何处理该服务。返回值必须是下面几个值: START_STICKY START_REDELIVER_INTENT 启动Service 你可以从一个Activity或者其他组件调用startService(intent)来启动服务。Android系统会调用服务的onStartCommand()函数并且传给它intent。 用上一节的HelloService来做个例子: 如果服务没有提供绑定,那么通过startService()函数传入的intent就是应用组件和服务进行交互的唯一途径。如果你想服务发送结果给客户组件,那么客户组件需要在启动服务时,创建一个用于广播的PendingIntent,通过intent投递给服务。这样,服务就可以利用广播把结果发送给客户组件。 多个请求会导致服务的onStartCommand()被调用多次。但是,只需要一个停止请求(stopSelf()或stopService())就会使服务停止。 停止服务 一个启动的服务必须管理自己的生命周期。因为除非系统需要回收资源的时候,系统不会停止或者销毁服务。所以,服务必须通过调用stopSelf()来停止自己,或者有其他组件调用stopService()。 一担收到stopSelf()或stopService()的停止请求,系统会立刻销毁服务。 如果你的服务同时处理多个服务请求,当某个请求完成时就不能马上停止服务,因为你可能已经又接受了一个新的请求(在第一个请求完成时结束服务会终止第二个请求)。为了解决这个问题,你可以调用stopSelf(int)函数来保证你的停止请求总是基于最近的一次服务请求。这是因为,调用stopSelf(int)函数 注意:stopSelf(int)函数只是简单的与最近一次收到的startId比较,如果你的服务处理过程是多线程的,可能后收到的服务请求先完成,那stopSelf(int)的方案不适合你,你应该手动管理接受到的服务请求和完成的服务,比如在onStartCommand()函数中把startId记录到一个表中,在完成服务任务时在表中记录完成状态,在确保表中任务都完成的情况下直接调用stopSelf()来停止服务。 在前台运行服务 一个前台服务是用户能够很明显意识到的服务,当可用内存比较低的时候,系统不会杀掉前台服务。一个前台服务必须提供一个状态栏通知,放在正在运行条目里,这意味着只要服务没有停止或者一直是前台服务,这个通知就不会被消失。 举个例子,一个音乐播放器服务应该被设置为前台运行,因为用户非常明显知道他在运行。这个状态栏通知可以显示正在播放的歌曲,并且可以允许用户点击进入音乐播放界面。 要使服务运行在前台只要调用startForeground()。这个方法有两个参数:一个通知的整数ID和一个状态栏通知。代码片段: 使用stopForeground()函数可以把服务从前台移除。这个函数带一个布尔值参数,来表示是否从状态栏移除通知。这个函数不会使服务停止。如果把前台服务停止掉,那么通知也会同时被移除。
publicclassHelloServiceextendsService{
privateLoopermServiceLooper;
privateServiceHandlermServiceHandler;
privatefinalclassServiceHandlerextendsHandler{
publicServiceHandler(Looperlooper){
super(looper);
}
@Override
publicvoidhandleMessage(Messagemsg){
//Normallywewoulddosomeworkhere,likedownloadafile.
//Foroursample,wejustsleepfor5seconds.
longendTime=System.currentTimeMillis()+5*1000;
while(System.currentTimeMillis()<endTime){
synchronized(this){
try{
wait(endTime-System.currentTimeMillis());
}catch(Exceptione){
}
}
}
//StoptheserviceusingthestartId,sothatwedon"tstop
//theserviceinthemiddleofhandlinganotherjob
stopSelf(msg.arg1);
}
}
publicvoidonCreate(){
//Startupthethreadrunningtheservice. Notethatwecreatea
//separatethreadbecausetheservicenormallyrunsintheprocess"s
//mainthread,whichwedon"twanttoblock. Wealsomakeit
//backgroundprioritysoCPU-intensiveworkwillnotdisruptourUI.
HandlerThreadthread=newHandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper=thread.getLooper();
mServiceHandler=newServiceHandler(mServiceLooper);
}
publicintonStartCommand(Intentintent,intflags,intstartId){
Toast.makeText(this,"servicestarting",Toast.LENGTH_SHORT).show();
//startIDsoweknowwhichrequestwe"restoppingwhenwefinishthejob
Messagemsg=mServiceHandler.obtainMessage();
msg.arg1=startId;
mServiceHandler.sendMessage(msg);
returnSTART_STICKY;
}
publicIBinderonBind(Intentintent){
//Wedon"tprovidebinding,soreturnnull
returnnull;
}
publicvoidonDestroy(){
Toast.makeText(this,"servicedone",Toast.LENGTH_SHORT).show();
}
}
START_NOT_STICKY
在onStartCommand()返回后,系统杀死服务,服务将不会重启,除非有pendingintents(目前笔者还不懂什么是pendingIntents)要投递。这比较适合非常容易就可以重新启动未完成任务的情况。
在系统杀死服务后,重启服务并且调用onStartCommand(),但是不重新投递上一次的intent。系统会传给onStartCommand()函数null,除非有pendingintent来启动服务,会传给onStartCommand()相应的intent。这种做法比较适合媒体播放服务,不需要执行命令,但是独立运行,常处于等待任务的服务。
在系统杀死服务后,重启服务并且调用onStartCommand(),参数传入上一次的intent,然后接下来是pendingintent传入onStartCommand()。这比较适合于正在执行一项工作,它不能被立刻恢复,例如下载文件。
Intentintent=newIntent(this,HelloService.class);
startService(intent);
startService()会立刻返回,Android系统会调用服务的onStartCommand()函数。如果这是服务没有在运行,系统会首先调用onCreate()函数,然后会紧接着调用onStartCommand()函数。
会把onStartCommand()函数传入的startId传给停止请求。当你的startId和最近一次接受的服务请求不匹配时,服务不会结束。
Notificationnotification=newNotification(R.drawable.icon,getText(R.string.ticker_text),
System.currentTimeMillis());
IntentnotificationIntent=newIntent(this,ExampleActivity.class);
PendingIntentpendingIntent=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);
相关文章