Android之Service例程
2015-08-10 18:22
344 查看
转载/article/2781421.html
一个服务是一个应用程序组合,在后台运行,可以执行一个长时间的操作,但是并不提供用户界面。
应用程序终止,Service也不会终止。。。。每个Service必须在manifest中
通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。。Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
service的两种模式(startService()/bindService()不是完全分离的):
本地服务LocalService用于应用程序内部。
它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf()或Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服。用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
远程服务RemoteService用于android系统内部的应用程序之间。
它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
两种Service方式启动服务的主要区别
1、startService()方式启动。
使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法(在2.0之后已经改变onStartCommond()方法)。
如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。或者自己停止。
2、bindService()方式启动;(异步)
调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用
采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法
Service生命周期:(如图,不做介绍)
拥有service的进程具有较高的优先级
官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级
1、如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
2、如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
3、如果客户端已经连接到service(bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
4、如果service可以使用startForeground(int,Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
分析onStartCommand方法参数的作用和返回值的作用:
1、根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,(当进行被杀死的时候,是否重新启动。如果是参数:START_REDELIVER_INTENT表示当服务所在进程被杀死后,重新启动,并且重新传递Intent内容,其它两个参数不会重新传递intent,都为null)
2、返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
3、是当前服务的标记
4、第三个参数startId表示当前启动的Service的次数。
下面看一下测试源码:
HelloSerivce.java
[java]
viewplaincopyprint?
publicclassHelloServiceextendsService{
Handlerhandler=newHandler();
privatefinalIBindermBinder=newHelloBinder();
@Override
publicvoidonCreate(){
Log.v("verbose","onCreate");
super.onCreate();
}
/**
*用这种方式,从Activity启动服务之后,在后台运行的,之后就没有与Activity联系了如果有bind方法
*,在整个过程中与Activity进行通信
*
*根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,
*START_REDELIVER_INTENT服务被系统杀死后是否自动重启,和是否重新传递intent。
*如果被杀死之后重新启动服务,会重新调用onCreate,和onStartCommand方法
*,但是重新调用onStartCommand的时候,不会再次传递参数。。
*返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
*/
@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
Log.v("verbose","onStartComand");
handler.post(newRunnable(){//用通常用Handler线程跟UI线程打交到
@Override
publicvoidrun(){
Toast.makeText(getApplicationContext(),"启动服务",
Toast.LENGTH_LONG).show();
}
});
//returnsuper.onStartCommand(intent,flags,startId);
returnSTART_REDELIVER_INTENT;
}
@Override
publicvoidonDestroy(){
Log.v("verbose","onDestory");
handler.post(newRunnable(){//用通常用Handler线程跟UI线程打交到
@Override
publicvoidrun(){
Toast.makeText(getApplicationContext(),"停止服务",
Toast.LENGTH_LONG).show();
}
});
super.onDestroy();
}
/**
*这个方法是必须执行的,当用bind方法启动Service的时候,是有用的。
*/
@Override
publicIBinderonBind(Intentintent){
//TODOAuto-generatedmethodstub
returnmBinder;
}
/**
*ClassusedfortheclientBinder.Becauseweknowthisservicealways
*runsinthesameprocessasitsclients,wedon'tneedtodealwithIPC.
*/
publicclassHelloBinderextendsBinder{
HelloServicegetService(){
returnHelloService.this;
}
}
publicvoidshowNumber(){
newThread(newRunnable(){
inti=1;
@Override
publicvoidrun(){
while(true){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(i++);
}
}
}).start();
}
}
HelloServiceActivity.java
[java]
viewplaincopyprint?
packagehb.android.service;
importhb.android.service.HelloService.HelloBinder;
importandroid.app.Activity;
importandroid.content.ComponentName;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.ServiceConnection;
importandroid.os.Bundle;
importandroid.os.IBinder;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.TextView;
publicclassHelloServiceActivityextendsActivity{
Intentintent;
booleanflag=true;
HelloServicemService;;
booleanmBound=false;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent=newIntent();
initMyWidget();
setMyWidgetListener();
}
publicvoidsetMyWidgetListener(){
MyWidget.btn_bind.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_start.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_stop.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_unbind.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_kill.setOnClickListener(newWidgetOnClickListener());
}
classWidgetOnClickListenerimplementsOnClickListener{
@Override
publicvoidonClick(Viewv){
switch(v.getId()){
caseR.id.btn_start:
intent.setClass(getApplicationContext(),HelloService.class);
intent.putExtra("test","start");
startService(intent);
flag=true;
MyWidget.btn_stop.setEnabled(flag);
break;
caseR.id.btn_stop:
intent.putExtra("test","stop");
stopService(intent);
flag=false;
MyWidget.btn_stop.setEnabled(flag);
break;
caseR.id.btn_kill:
android.os.Process.killProcess(android.os.Process.myPid());
break;
caseR.id.btn_bind:
Intentintent=newIntent(getApplicationContext(),HelloService.class);
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);//自动调用Service里的onCreate方法
System.out.println("bind:"+mService);
opeService();
break;
caseR.id.btn_unbind:
if(mBound){
unbindService(mConnection);//自动调用Service的onDestory方法
mBound=false;
}
break;
default:
break;
}
}
publicvoidopeService(){
System.out.println("opeService:"+mService);
//mService.showNumber();
}
}
publicvoidinitMyWidget(){
MyWidget.btn_bind=(Button)findViewById(R.id.btn_bind);
MyWidget.btn_start=(Button)findViewById(R.id.btn_start);
MyWidget.btn_stop=(Button)findViewById(R.id.btn_stop);
MyWidget.btn_unbind=(Button)findViewById(R.id.btn_unbind);
MyWidget.tv_test=(TextView)findViewById(R.id.tv_test);
MyWidget.btn_kill=(Button)findViewById(R.id.btn_kill);
}
privatestaticclassMyWidget{
staticButtonbtn_start;
staticButtonbtn_stop;
staticButtonbtn_bind;
staticButtonbtn_unbind;
staticButtonbtn_kill;
@SuppressWarnings("unused")
staticTextViewtv_test;
}
@Override
protectedvoidonDestroy(){
super.onDestroy();
stopService(intent);
}
/**Definescallbacksforservicebinding,passedtobindService()*/
privateServiceConnectionmConnection=newServiceConnection(){
publicvoidonServiceConnected(ComponentNameclassName,
IBinderservice){
//We'veboundtoLocalService,casttheIBinderandgetLocalServiceinstance
HelloBinderbinder=(HelloBinder)service;
mService=binder.getService();
System.out.println("ServiceConnection:"+mService);
mBound=true;
mService.showNumber();
}
@Override
publicvoidonServiceDisconnected(ComponentNamearg0){
mBound=false;
}
};
@Override
protectedvoidonStop(){
super.onStop();
if(mBound){
unbindService(mConnection);
mBound=false;
}
};
}
注意:当服务创建之后由,onServiceConnected这个方法负责建立与Servicer的连接
意思当Activit用BindService启动服务之后,由:
[java]
viewplaincopyprint?
publicServiceConnectionmConnection=newServiceConnection(){
@Override
publicvoidonServiceDisconnected(ComponentNamename){
System.out.println("onServiceConnected");
mBound=false;
}
/**
*服务创建之后收些方法建立Serivce与Activity的连接
*/
@Override
publicvoidonServiceConnected(ComponentNamename,IBinderservice){
System.out.println("onServiceDisconnected");
mBound=true;
LocalBindermyBinder=(LocalBinder)service;
myService=myBinder.getService();//在下面就可以对service进行操作了。
myService.showNumber();
}
};
对所绑定的Service进行控制(连接与销毁)
一个服务是一个应用程序组合,在后台运行,可以执行一个长时间的操作,但是并不提供用户界面。
应用程序终止,Service也不会终止。。。。每个Service必须在manifest中
通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。。Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
service的两种模式(startService()/bindService()不是完全分离的):
本地服务LocalService用于应用程序内部。
它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf()或Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服。用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
远程服务RemoteService用于android系统内部的应用程序之间。
它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
两种Service方式启动服务的主要区别
1、startService()方式启动。
使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法(在2.0之后已经改变onStartCommond()方法)。
如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。或者自己停止。
2、bindService()方式启动;(异步)
调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用
采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法
Service生命周期:(如图,不做介绍)
拥有service的进程具有较高的优先级
官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级
1、如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
2、如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
3、如果客户端已经连接到service(bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
4、如果service可以使用startForeground(int,Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
分析onStartCommand方法参数的作用和返回值的作用:
1、根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,(当进行被杀死的时候,是否重新启动。如果是参数:START_REDELIVER_INTENT表示当服务所在进程被杀死后,重新启动,并且重新传递Intent内容,其它两个参数不会重新传递intent,都为null)
2、返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
3、是当前服务的标记
4、第三个参数startId表示当前启动的Service的次数。
下面看一下测试源码:
HelloSerivce.java
[java]
viewplain
publicclassHelloServiceextendsService{
Handlerhandler=newHandler();
privatefinalIBindermBinder=newHelloBinder();
@Override
publicvoidonCreate(){
Log.v("verbose","onCreate");
super.onCreate();
}
/**
*用这种方式,从Activity启动服务之后,在后台运行的,之后就没有与Activity联系了如果有bind方法
*,在整个过程中与Activity进行通信
*
*根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,
*START_REDELIVER_INTENT服务被系统杀死后是否自动重启,和是否重新传递intent。
*如果被杀死之后重新启动服务,会重新调用onCreate,和onStartCommand方法
*,但是重新调用onStartCommand的时候,不会再次传递参数。。
*返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
*/
@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
Log.v("verbose","onStartComand");
handler.post(newRunnable(){//用通常用Handler线程跟UI线程打交到
@Override
publicvoidrun(){
Toast.makeText(getApplicationContext(),"启动服务",
Toast.LENGTH_LONG).show();
}
});
//returnsuper.onStartCommand(intent,flags,startId);
returnSTART_REDELIVER_INTENT;
}
@Override
publicvoidonDestroy(){
Log.v("verbose","onDestory");
handler.post(newRunnable(){//用通常用Handler线程跟UI线程打交到
@Override
publicvoidrun(){
Toast.makeText(getApplicationContext(),"停止服务",
Toast.LENGTH_LONG).show();
}
});
super.onDestroy();
}
/**
*这个方法是必须执行的,当用bind方法启动Service的时候,是有用的。
*/
@Override
publicIBinderonBind(Intentintent){
//TODOAuto-generatedmethodstub
returnmBinder;
}
/**
*ClassusedfortheclientBinder.Becauseweknowthisservicealways
*runsinthesameprocessasitsclients,wedon'tneedtodealwithIPC.
*/
publicclassHelloBinderextendsBinder{
HelloServicegetService(){
returnHelloService.this;
}
}
publicvoidshowNumber(){
newThread(newRunnable(){
inti=1;
@Override
publicvoidrun(){
while(true){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(i++);
}
}
}).start();
}
}
HelloServiceActivity.java
[java]
viewplain
packagehb.android.service;
importhb.android.service.HelloService.HelloBinder;
importandroid.app.Activity;
importandroid.content.ComponentName;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.ServiceConnection;
importandroid.os.Bundle;
importandroid.os.IBinder;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.TextView;
publicclassHelloServiceActivityextendsActivity{
Intentintent;
booleanflag=true;
HelloServicemService;;
booleanmBound=false;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent=newIntent();
initMyWidget();
setMyWidgetListener();
}
publicvoidsetMyWidgetListener(){
MyWidget.btn_bind.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_start.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_stop.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_unbind.setOnClickListener(newWidgetOnClickListener());
MyWidget.btn_kill.setOnClickListener(newWidgetOnClickListener());
}
classWidgetOnClickListenerimplementsOnClickListener{
@Override
publicvoidonClick(Viewv){
switch(v.getId()){
caseR.id.btn_start:
intent.setClass(getApplicationContext(),HelloService.class);
intent.putExtra("test","start");
startService(intent);
flag=true;
MyWidget.btn_stop.setEnabled(flag);
break;
caseR.id.btn_stop:
intent.putExtra("test","stop");
stopService(intent);
flag=false;
MyWidget.btn_stop.setEnabled(flag);
break;
caseR.id.btn_kill:
android.os.Process.killProcess(android.os.Process.myPid());
break;
caseR.id.btn_bind:
Intentintent=newIntent(getApplicationContext(),HelloService.class);
bindService(intent,mConnection,Context.BIND_AUTO_CREATE);//自动调用Service里的onCreate方法
System.out.println("bind:"+mService);
opeService();
break;
caseR.id.btn_unbind:
if(mBound){
unbindService(mConnection);//自动调用Service的onDestory方法
mBound=false;
}
break;
default:
break;
}
}
publicvoidopeService(){
System.out.println("opeService:"+mService);
//mService.showNumber();
}
}
publicvoidinitMyWidget(){
MyWidget.btn_bind=(Button)findViewById(R.id.btn_bind);
MyWidget.btn_start=(Button)findViewById(R.id.btn_start);
MyWidget.btn_stop=(Button)findViewById(R.id.btn_stop);
MyWidget.btn_unbind=(Button)findViewById(R.id.btn_unbind);
MyWidget.tv_test=(TextView)findViewById(R.id.tv_test);
MyWidget.btn_kill=(Button)findViewById(R.id.btn_kill);
}
privatestaticclassMyWidget{
staticButtonbtn_start;
staticButtonbtn_stop;
staticButtonbtn_bind;
staticButtonbtn_unbind;
staticButtonbtn_kill;
@SuppressWarnings("unused")
staticTextViewtv_test;
}
@Override
protectedvoidonDestroy(){
super.onDestroy();
stopService(intent);
}
/**Definescallbacksforservicebinding,passedtobindService()*/
privateServiceConnectionmConnection=newServiceConnection(){
publicvoidonServiceConnected(ComponentNameclassName,
IBinderservice){
//We'veboundtoLocalService,casttheIBinderandgetLocalServiceinstance
HelloBinderbinder=(HelloBinder)service;
mService=binder.getService();
System.out.println("ServiceConnection:"+mService);
mBound=true;
mService.showNumber();
}
@Override
publicvoidonServiceDisconnected(ComponentNamearg0){
mBound=false;
}
};
@Override
protectedvoidonStop(){
super.onStop();
if(mBound){
unbindService(mConnection);
mBound=false;
}
};
}
注意:当服务创建之后由,onServiceConnected这个方法负责建立与Servicer的连接
意思当Activit用BindService启动服务之后,由:
[java]
viewplain
publicServiceConnectionmConnection=newServiceConnection(){
@Override
publicvoidonServiceDisconnected(ComponentNamename){
System.out.println("onServiceConnected");
mBound=false;
}
/**
*服务创建之后收些方法建立Serivce与Activity的连接
*/
@Override
publicvoidonServiceConnected(ComponentNamename,IBinderservice){
System.out.println("onServiceDisconnected");
mBound=true;
LocalBindermyBinder=(LocalBinder)service;
myService=myBinder.getService();//在下面就可以对service进行操作了。
myService.showNumber();
}
};
对所绑定的Service进行控制(连接与销毁)
相关文章推荐
- Android基础:广播接收器及其生命周期介绍
- Android CircleProgressBar好看的圆形进度条
- 从Android源码分析View绘制
- Android 录音功能(语音录制保存,播放)
- 星云测试- Android应用深度体检专业平台
- Android基 4000 础:Service及其生命周期介绍
- 让Android Support V4中的SwipeRefreshLayout支持上拉加载更多
- Android 为PopupWindow设置动画效果
- Android Animation动画(很详细)
- android屏幕适配不同的资源图片、布局
- Android多媒体框架分析-AudioFlinger
- Android里面怎么让界面居中
- Android运行时异常“Binary XML file line # : Error inflating class”
- Android中的图片资源
- Android Dialog 系统样式讲解及透明背景
- Android Sqlite数据库增删改查操作
- Android动画Animation的两种加载执行方式
- android用SP,判断是否过了一天
- user interface, view 和activity究竟是啥?
- Activity重要知识总结