`
kanwoerzi
  • 浏览: 1646745 次
文章分类
社区版块
存档分类
最新评论

Service

 
阅读更多
publicabstractclass
Service
extendsContextWrapper
implementsComponentCallbacks
java.lang.Object
android.content.Context
android.content.ContextWrapper
android.app.Service
ClassOverview
AServiceisanapplicationcomponentrepresentingeitheranapplication'sdesiretoperformalonger-runningoperation
whilenotinteractingwiththeuserortosupplyfunctionalityforotherapplicationstouse.Eachserviceclassmusthaveacorresponding<service>declarationinitspackage'sAndroidManifest.xml.ServicescanbestartedwithContext.startService()andContext.bindService().
Notethatservices,likeotherapplicationobjects,runinthemainthreadoftheirhostingprocess.Thismeansthat,ifyourserviceisgoingtodoanyCPUintensive(suchasMP3playback)orblocking(suchasnetworking)operations,itshouldspawnitsownthreadinwhichtodothatwork.MoreinformationonthiscanbefoundinApplicationFundamentals:ProcessesandThreads.TheIntentServiceclassisavailableasastandardimplementationofServicethathasitsownthreadwhereitschedulesitsworktobedone.

Service主要用来处理运行在后台的耗时操作。每个Service必须在AndroidManifest.xml中进行声明。可以通过Context.startService()andContext.bindService()来启动Service。Service也是运行在主要线程的。所以如果想要做些非常耗CPU(放MP3)或阻塞操作(网络),最好自己新建个线程来做这些工作。IntentService就是一个Intent的标准实现哦。它拥有它自己的线程。
什么是Service呢?
有两个需要强调的概念是:
*AServiceisnotaseparateprocess.
TheServiceobjectitselfdoesnotimplyitisrunninginitsownprocess;
unlessotherwisespecified,itrunsinthesameprocessastheapplicationitispartof.

Service本身并没有运行在一个单独的进程上面。如果没有特殊的规定,它运行在它所在的那个应用程序的进程上面。
*AServiceisnotathread.Itisnotameansitselftodoworkoffofthemainthread(toavoidApplicationNotRespondingerrors).
Service也不是个线程。他本身也运行在主线程中。它本身并不能避免应用程序没有响应的错误

ThusaServiceitselfisactuallyverysimple,providingtwomainfeatures:
然而Service实际上本身是很简单的,它主要有以下两个属性
*Afacilityfortheapplicationtotellthesystemaboutsomethingitwantstobedoinginthebackground
(evenwhentheuserisnotdirectlyinteractingwiththeapplication).ThiscorrespondstocallstoContext.startService(),whichaskthesystemtoscheduleworkfortheservice,toberununtiltheserviceorsomeoneelseexplicitlystopit.
Service只是告诉系统,它是运行在后台。调用Context.startService(),系统就会安排service来运行,直到它自己或别人显式的停止它.
*Afacilityforanapplicationtoexposesomeofitsfunctionalitytootherapplications.
ThiscorrespondstocallstoContext.bindService(),whichallowsalong standingconnectiontobemadetotheserviceinordertointeractwithit.
Service为进程之间通信提供了便利。可以通过调用Context.bindService()来实现。对于本地的通信也提供方便。
对于本地通信也是通过Context.bindService(),只是不用提供AIDL来声明远程接口。

当Service被创建时,所有这些系统实际所做的是实例化该组件并调用它的OnCreate()和主线程上的任何其他合适的回调。
Service任何时候最多只有一个实例。多此次调用Context.startService,不会产生多个实例。通常,在Service中新建一个线程。让该线程来做些耗时的工作。

Service的本身生命周期
1,当调用Context.startService()时,如果Service还没创建就会调用onCreate(),然后调用onStartCommand(Intent,int,int),
如果已经创建,就不会掉用onCreate(),直接调用onStartCommand(Intent,int,int)。
Service创建后直到调用Context.stopService()orstopSelf()才回消亡。 如果使用stopSelf(intstartId)的话,它直到startId的那个Intent被执行完才消亡.这里的startId对应于onStartCommand(Intent,int,int)的第三个参数startId。

2,当Service启动后,它的有三种运行模式。它取决于从onStartCommand()中返回的值。
2.1,如果是START_STICKY就说明它是显式启动的,也要显式的来停止.即如果它因为内存的原因被系统杀死了的话,系统可以让它重生。 注意它在被杀死时,不会保存已经发送了的Intent.如果重生时,没有未处理的Intent,
那么onStartCommand(Intent,int,int)中的Intent就是null,

2.2,如果是START_NOT_STICKY当它因为内存的原因被系统杀死的时候,如果没有Intent需要传送。
那么即使内存充足的是时候,它也不会立即被重新创建启动。它要直到Context.startService(Intent),才重新被创建启动。

2.3,如果是START_REDELIVER_INTENT,当它因为内存的原因被系统杀死。那么内存充足的是时候,它立即被重新创建启动。
这时它在被杀死钱前传递的那个Intent会再次传递到onStartCommand(Intent,int,int)中,因此其不可能Intent就是null

3,客户也可以使用Context.bindService()来取得和服务的永久性链接.如果服务没有启动,那么这将创建它(调用onCreate()),
但不会调用onStartCommand().客户将获取IBinder对象,这些对象由服务的onBind(Intent)方法返回,
以便客户能够向服务发出调用.只要链接建立,服务就会一直运行(不管客户是否保留服务的IBinder的引用).

通常IBinder是使用aidl写成的一个复杂接口.
4,Service可以同时以start和绑定连接的方式使用。这时只要有start的没有stop,或至少有一个通过Context.BIND_AUTO_CREATE来绑定的连接没有断开,那么Service就不会调onDestroy()方法,也不会消亡。
Permissions
如果一个服务在manifest中的<service>中声明一个服务的强制全局访问,
那么其它的应用程序必须在对应的<user-permission>元素中做相应权限的声明,以便启动,停止或者绑定该服务.
此外,一个服务可以使用权限来保护一个IPC调用.使用checkCallingPermission(String)方法.

ProcessLifecycle进程生命周期
android系统会试图保持持有服务的进程运行,只要该服务被启动或者有客户连接它.
当内存不足时,持有服务的进程将有较高的优先级
1,如果服务正在运行onCreate(),onStartCommand()或者onDestroy()的代码,那么持有服务的进程将变为前台进程。
它是不会被系统杀死的。

2,当Service被创建后,他所驻留的进程虽然比可见的进程优先级低,但是它比不可见的进程高。
因为大多数进程都是不可见的,所有Service也只会在内存非常低的时候才被系统杀死。

3,如果有客户端绑定到了Service,那么该Service所驻留的优先级就不比该客户端的进程低。
即如果该客户端是可见的话,那么该进程就和可见的线程的优先级一样。

4,一个已启动的服务可以通过调研startForeground(int,Notification)API来将服务放在前台状态,
系统认为它是用户可见的,因此在内存低的时候不会被kill. 当然从理论上来说它也可能在当前应用程序面临巨大内存不足的情况下被杀死,但一般不考虑这种情况。

注意1:通过上面我们知道大部分服务在运行的时候,它有可能被系统Kill掉.这样,系统之后会重启该服务.
如果你实现onStartCommand()来安排异步工作或者在另一个线程中工作, 那么你可能需要使用
START_FLAG_REDELIVERY来让系统重新发送一个intent。这样如果你的服务在处理它的时候被Kill掉,Intent不会丢失.
注意2:应用程序进程的优先级是由其包中正在运行的程序组件(service,Activity)中最高者决定的。
例1:start启动方式。并没处理什么实质的工作
Buttonbutton3=(Button)findViewById(R.id.Button03);
OnClickListenerlistener3=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent(Hello.this,MyService.class);
startService(intent);
}
};
button3.setOnClickListener(listener3);
Buttonbutton4=(Button)findViewById(R.id.Button04);
OnClickListenerlistener4=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent(Hello.this,MyService.class);
stopService(intent);
}
};
button4.setOnClickListener(listener4);

mainfest.xml文件中
<serviceandroid:name=".MyService"></service>
MyService.java文件
importandroid.app.Service;
importandroid.content.Intent;
importandroid.os.IBinder;
importandroid.util.Log;
publicclassMyServiceextendsService{
Stringtag="hubin";
@Override
publicvoidonCreate(){
Log.i(tag,"oncreate");
}

@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
Log.i(tag,"Receivedstartid"+startId+":"+intent);
//Wewantthisservicetocontinuerunninguntilitisexplicitly
//stopped,soreturnsticky.
returnSTART_STICKY;
}
@Override
publicvoidonDestroy(){
Log.i(tag,"OnDestory");
}
@Override
publicIBinderonBind(Intentarg0){
//TODOAuto-generatedmethodstub
returnnull;
}
}
例2:start启动方式。已经可以处理工作,但没有通信
publicclassMyServiceextendsServiceimplementsRunnable{
Stringtag="hubin";
@Override
publicvoidonCreate(){
Log.i(tag,"oncreate");
}

@Override
publicint
onStartCommand(Intentintent,intflags,intstartId){
Log.i(tag,"Receivedstartid"+startId+":"+intent);
//Wewantthisservicetocontinuerunninguntilitisexplicitly
//stopped,soreturnsticky.
if(blRun==false)
{
Threadt=newThread(this);
t.start();
}
returnSTART_STICKY;
}

@Override
publicvoidonDestroy(){
blRun=false;
Log.i(tag,"OnDestory");
}

@Override
publicIBinderonBind(Intentarg0){
//TODOAuto-generatedmethodstub
returnnull;
}

booleanblRun=false;
finalstaticintkSleepTime=5;
publicvoidrun()
{
blRun=true;
while(blRun)
{
Log.i(tag,"run"+System.currentTimeMillis());
try{
Thread.sleep(kSleepTime);
}catch(InterruptedExceptione)
{
Log.e(tag,"InterruptedException",e);
}
}
}

}
例3:启动方式。可以处理工作,虽然没有通信,但是已经可以通过Intent来发命令。
Intentintent=newIntent(Hello.this,MyService.class);
Stringvalue="Hello"+System.currentTimeMillis();
intent.putExtra("cmd",value);
startService(intent);
importandroid.app.Service;
importandroid.content.Intent;
importandroid.os.IBinder;
importandroid.util.Log;
publicclassMyServiceextendsServiceimplementsRunnable{
Stringtag="hubin";
@Override
publicvoidonCreate(){
Log.i(tag,"oncreate");
}

@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
Log.i(tag,"Receivedstartid"+startId+":"+intent);
//Wewantthisservicetocontinuerunninguntilitisexplicitly
//stopped,soreturnsticky.
if(blRun==false)
{
Threadt=newThread(this);
t.start();
}
if(intent!=null)
{
Stringcmd=intent.getStringExtra("cmd");
if(cmd!=null)
{
addCmd(cmd);
}

}
returnSTART_STICKY;
}

@Override
publicvoidonDestroy(){
blRun=false;
Log.i(tag,"OnDestory");
}

@Override
publicIBinderonBind(Intentarg0){
//TODOAuto-generatedmethodstub
returnnull;
}
booleanblRun=false;
finalstaticintkSleepTime=5;
finalStringcmdPool[]=newString[10];
intcmdStartCursor=-1;
intcmdEndCursor=-1;
publicvoidrun()
{
blRun=true;
while(blRun)
{
if(cmdStartCursor!=cmdEndCursor)
{
cmdStartCursor=(cmdStartCursor+1)%cmdPool.length;
Log.i(tag,"run:"+cmdPool[cmdStartCursor]);
}
try{
Thread.sleep(kSleepTime);
}catch(InterruptedExceptione)
{
Log.e(tag,"InterruptedException",e);
}
}
}
voidaddCmd(Stringcmd)
{
if((cmdEndCursor+1)%cmdPool.length!=cmdStartCursor)
{
cmdEndCursor++;
cmdEndCursor=cmdEndCursor%cmdPool.length;
cmdPool[cmdEndCursor]=cmd;
}
}
}
例4:绑定方式。可以处理工作,实现了进程的本地通信
importandroid.app.Activity;
importandroid.content.ComponentName;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.ServiceConnection;
importandroid.net.Uri;
importandroid.os.Bundle;
importandroid.os.IBinder;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.util.Log;
publicclassHelloextendsActivity{
finalstaticStringtag="hubin";
/**Calledwhentheactivityisfirstcreated.*/
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
..............................
Buttonbutton4=(Button)findViewById(R.id.Button04);
OnClickListenerlistener4=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent(Hello.this,MyService.class);
stopService(intent);
}
};
button4.setOnClickListener(listener4);

Buttonbutton5=(Button)findViewById(R.id.Button05);
OnClickListenerlistener5=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
doBindService();
}
};
button5.setOnClickListener(listener5);
Buttonbutton6=(Button)findViewById(R.id.Button06);
OnClickListenerlistener6=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
doUnbindService();
}
};
button6.setOnClickListener(listener6);

Buttonbutton7=(Button)findViewById(R.id.Button07);
OnClickListenerlistener7=newOnClickListener(){
@Override
publicvoidonClick(Viewv){
if(mBoundService==null)
{
Log.i(tag,"theServicehasnotbind!Pleasebindtheservicefirst");
return;
}
Stringcmd="Hello:"+System.currentTimeMillis()%100;
mBoundService.addCmd(cmd);
}
};
button7.setOnClickListener(listener7);
}
privateMyServicemBoundService;

privateServiceConnectionmConnection=newServiceConnection(){
publicvoid
onServiceConnected(ComponentNameclassName,IBinderservice){
mBoundService=((MyService.LocalBinder)service).getService();
}

publicvoid
onServiceDisconnected(ComponentNameclassName){
mBoundService=null;
}
};

booleanmIsBound=true;
voiddoBindService(){
//Establishaconnectionwiththeservice.Weuseanexplicit
//classnamebecausewewantaspecificserviceimplementationthat
//weknowwillberunninginourownprocess(andthuswon'tbe
//supportingcomponentreplacementbyotherapplications).
bindService(newIntent(Hello.this,
MyService.class),mConnection,Context.BIND_AUTO_CREATE);

mIsBound=true;
}
voiddoUnbindService(){
if(mIsBound){
//Detachourexistingconnection.
unbindService(mConnection);
mIsBound=false;
}
}
@Override
protectedvoidonDestroy(){
super.onDestroy();
doUnbindService();
}
}
例4:绑定方式。可以处理工作,实现了两个进程的通信
具体参照《AIDL和Service实现两进程通信
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics