一、基础概念
Service是Android中一个类,它是Android四大组件之一,使用Service可以在后台执行长时间的操作( perform long-running operations in the background ),Service并不与用户产生UI交互。其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行。一个组件可以与Service绑定并与之交互,甚至是跨进程通信(IPC)。例如,一个Service可以在后台执行网络请求、播放音乐、执行文件读写操作或者与 content provider交互 等。
Services有两种启动形式:
Started:其他组件调用startService()方法启动一个Service。一旦启动,Service将一直运行在后台,即便启动Service的组件已被destroy。通常,一个被start的Service会在后台执行单独的操作,也并不给启动它的组件返回结果。比如说,一个start的Service执行在后台下载或上传一个文件的操作,完成之后,Service应自己停止。
Bound:其他组件调用bindService()方法绑定一个Service。通过绑定方式启动的Service是一个client-server结构,该Service可以与绑定它的组件进行交互。一个bound service仅在有组件与其绑定时才会运行,多个组件可与一个service绑定,service不再与任何组件绑定时,该service会被destroy。
请注意:Service运行在主线程中(A service runs in the main thread of its hosting process),Service并不是一个新的线程,也不是新的进程。也就是说,若您需要在Service中执行较为耗时的操作(如播放音乐、执行网络请求等),需要在Service中创建一个新的线程(强烈建议使用IntentService)。这可以防止ANR的发生,同时主线程可以执行正常的UI操作
二、代码说话-startService
新建类,继承Service,然后实现它的onBind()方法,同时重写它的几个方法打印下生命周期
public class MyService extends Service { private static final String TAG = "dah_MyService"; @Override public void onCreate() { super.onCreate(); Log.e(TAG, "onCreate: "); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e(TAG, "onStartCommand: "); return super.onStartCommand(intent, flags, startId); } @Override public void onStart(Intent intent, int startId) { Log.e(TAG, "onStart: "); super.onStart(intent, startId); } @Nullable @Override public IBinder onBind(Intent intent) { Log.e(TAG, "onBind: "); return null; } @Override public void onDestroy() { super.onDestroy(); Log.e(TAG, "onDestroy: "); }
service作为四大组件之一,是需要在AndroidManifest.xml中注册的
<service android:name=".service.MyService"/>
在MainActivity中添加两个Button,分别调用startService、stopService方法(不上代码了)
mBtnStartService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, MyService.class);
startService(intent);
}
});
mBtnStopService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, MyService.class);
stopService(intent);
}
});
运行后,点击启动按钮,Log输入显示,依次调用了onCreate()->onStartCommand()->onStart(),
03-14 10:51:43.756 16073-16073/com.yanftch.basic E/dah_MyService: onCreate:
03-14 10:51:43.756 16073-16073/com.yanftch.basic E/dah_MyService: onStartCommand:
03-14 10:51:43.756 16073-16073/com.yanftch.basic E/dah_MyService: onStart:
再次点击启动按钮,会发现只调用了onStartCommand()->onStart(),证实了onCreate()方法只会调用一次
03-14 10:51:43.756 16073-16073/com.yanftch.basic E/dah_MyService: onCreate:
03-14 10:51:43.756 16073-16073/com.yanftch.basic E/dah_MyService: onStartCommand:
03-14 10:51:43.756 16073-16073/com.yanftch.basic E/dah_MyService: onStart:
03-14 10:53:10.323 16073-16073/com.yanftch.basic E/dah_MyService: onStartCommand:
03-14 10:53:10.323 16073-16073/com.yanftch.basic E/dah_MyService: onStart:
点击停止按钮,Log显示调用了onDestroy()方法,此时停止了Service
小结:
1.通过startService()启动Service,会依次调用onCreate()->onStartCommand()->onStart(),一旦Service启动成功,再次调用startService()时,只会调用onStartCommand()和onStart(),不会再调用onCreate(),也就是说onCreate()只会执行一次(该Service没有销毁时)。通过stopService()方法停止Service,会调用Service的onDestroy()方法。
2.onStartCommand()和onStart()的有什么关系。
在API 2.0之前,只有onStart()方法,而2.0之后,推荐使用onStartCommand()方法,其实onStartCommand()内部也是调用了onStart()方法,所以我们在开发中只重写onStartCommand()就可以了,而onStartCommand()方法的作用是告诉系统如何重启服务,如判断是否异常终止后重新启动,在何种情况下异常终止 等等。
3.在Service当中,如果有耗时操作,请开始子线程来执行
代码说话-bindService()
bindService(Intent service, ServiceConnection conn,int flags)
第一个参数:Intent指示对应的Service对象;
第二个参数:实现了 ServiceConnection接口的对象,conn是一个代表与service连接状态的类,当我们连接service成功或失败时,会主动触发其内部的onServiceConnected或onServiceDisconnected方法。如果我们想要访问service中的数据,可以在onServiceConnected()方法中进行实现;
第三个参数:Flags,在进行服务绑定时,其标志位可以为BIND_AUTO_CREATE、BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND等。其中BIND_AUTO_CREATE表示当收到绑定请求时,如果服务尚未创建,则即刻创建,在系统内存不足,需要先销毁优先级组件来释放内存,且只有驻留该服务的进程成为被销毁对象时,服务才可被销毁;BIND_DEBUG_UNBIND通常用于调试场景中判断绑定的服务是否正确,但其会引起内存泄漏,因此非调试目的不建议使用;BIND_NOT_FOREGROUND表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行
使用bindService()启动Service,这种模式是客户端-服务端模式(client-server),即服务端是Service,客户端是调用者,例如是某个Activity,客户端-服务端是可以相互通信的。
点击bind按钮,Log显示依次调用:onCreate–>onBind–>onServiceConnected
调用者和服务端已经绑定成功,建立连接。
如果再点一次,啥都没有,为啥?
我们在绑定Service的时候,如果service没被创建,那么调用一次onCreate(),然后调用onBind(),多次绑定时,不会多次调用onBind()。
点击unbind按钮,Log显示依次调用:onUnbind–>onDestroy
此时说明,Service已经停止了。细心的你,有没有发现有个方法没有调用?你知道是哪个方法吗?是—–>onServiceDisconnected()方法,为何我们解除绑定了,该回调方法没有调用呢?
03-14 11:21:37.711 21194-21194/com.yanftch.basic E/dah_MyBindService: onCreate:
03-14 11:21:37.711 21194-21194/com.yanftch.basic E/dah_MyBindService: onBind:
03-14 11:21:37.717 21194-21194/com.yanftch.basic E/dah_ServiceActivity: onServiceConnected: name===ComponentInfo{com.yanftch.basic/com.yanftch.basic.service.MyBindService} service===com.yanftch.basic.service.MyBindService$MyBinder@1fb98d1d
03-14 11:22:56.421 21194-21194/com.yanftch.basic E/dah_MyBindService: onUnbind:
03-14 11:22:56.422 21194-21194/com.yanftch.basic E/dah_MyBindService: onDestroy:
startService()和bindService()启动Service的区别
1.最经典的生命周期图,
2.两者和启动者的关系。
startService()启动的Service和启动者的生命周期无关,必须要显示调用stopService(intent)方法,才能停止该Service;
bindService()启动的Service和启动者的生命周期有关,当启动者销毁时,会自动销毁该Service。