Service
Service正如其名,是一种服务性质的组件,不能被用户所见,只能在后台运行,但是可以和其他组件进行交互,Service可以看做不可见的Activity,可以在后台有规律的执行某些操作,Service组件与其他的应用程序对象一样,是运行在启动它的主线程中,所以不可以在Service中进行耗时的操作,会阻塞主线程,但是可以在Service中启动新线程来进行操作,Service作为没有界面的长生命周期组件,可以用于媒体播放,记录用户地理位置信息等后台操作。
Service的启动模式
Service可以通过startService启动一个无绑定的Service,当启动这个Service的Activity被destroy的时候,Service继续运行在后台,不过这种方式启动的Service与Activity无交互,还有一种方式是通过bindService方法启动一个绑定的service,这种方式启动的Service可以与绑定的程序发生交互,但是在绑定的程序退出的时候,需要unbindService来解绑定,不然会有异常发生,还可以连续调用上面的两个函数,让Service同时具有上面两个的优点,当程序退出时,Service不销毁,而且可以与应用程序发生交互。
Service的生命周期
对于startService方式启动的服务来说,只有第一次启动的时候会调用onCreate() 方法,以后多次调用startService均只调用onStartCommand()方法(onStart()方法被弃用了),不论前面调用多少次startService,只需调用一次stopService即可停止服务,stopService多次调用没事,不会产生异常
对于bindService方式启动的服务来说,可以多次调用bindService,不过只有第一次有效,但是unbindService只能在服务正在运行的时候调用有效,当绑定服务没有运行的时候,调用此方法会产生异常
Service的使用
- 定义一个Service
定义一个Service,首先得继承android.app.Service,根据需要,覆写上面生命周期图中的回调函数
public class Service1 extends Service { @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { Log.v("x", "onCreate"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.v("x", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.v("x", "onDestroy"); super.onDestroy(); } }
可以看到,上面有一个特殊的onBind方法是必须覆写的,这个方法的默认返回null,如果通过startService方式启动Service,那么不用管这个回调函数,如果使用bindService启动服务,那么当绑定的时候,会回调这个函数,通过这个函数的返回值,启动服务的组件就可以与服务进行交互。
- 注册Service
与其他组件一样,当定义好一个Service以后,需要在配置文件中注册这个Service
<service android:name=".Service1" />
- 启动Service
startService启动:类似于其他组件,需要使用Intend对象
Intent intent = new Intent(); intent.setClass(this, Service1.class); startService(intent);
停止startService启动的服务
Intent intent = new Intent(); intent.setClass(this, Service1.class); stopService(intent);
bindService启动服务:
public boolean bindService (Intent service, ServiceConnection conn, int flags)
Intent service:一个Intent对象,用于指定启动的Service
ServiceConnection conn:一个ServiceConnection 对象,用于绑定时回调给绑定者
int flags:启动的标志,Service.BIND_AUTO_CREATE代表自动创建服务
Intent intent = new Intent(this, Service2.class); startService(intent); bindService(intent, conn, Service.BIND_AUTO_CREATE);
定义ServiceConnection 对象,ServiceConnection 是一个接口,我们需要new一个匿名内部类出来
ServiceConnection conn = new ServiceConnection() { @Override //当bind成功,onBind方法被调用以后调用此回调函数 public void onServiceConnected(ComponentName name, IBinder service) { Log.v("x", "Connected"); } //当绑定意外断开的时候调用此方法 @Override public void onServiceDisconnected(ComponentName name) { Log.v("x", "onServiceDisconnected"); } };
在ServiceConnection 的onServiceConnected()方法中,我们可以看到第二个参数为IBinder类型,这个参数就是Service中必须覆写的onBind方法的返回值,通过这个返回值,我们就可以获取服务的实例,从而调用服务中的方法。
完整的demo:
Service代码
public class Service2 extends Service { //自定义一个类继承自Binder class MyBinder extends Binder { //自定义方法,返回此Service的实例 public Service2 getService() { return Service2.this; } } @Override public IBinder onBind(Intent intent) { //此函数的返回值就是ServiceConnection的第二个参数 return new MyBinder(); } //Service自定义的四个方法 public void pro() { Log.v("x", "pro"); } public void stop() { Log.v("x", "stop"); } public void next() { Log.v("x", "next"); } public void play() { Log.v("x", "play"); } }
启动服务端的代码
public class MainActivity extends Activity { private Service2 service2; ServiceConnection conn = new ServiceConnection() { @Override //当bind成功,onBind方法被调用以后调用此回调函数 public void onServiceConnected(ComponentName name, IBinder service) { //获取服务实例 service2 = ((Service2.MyBinder) service).getService(); } //当绑定意外断开的时候调用此方法 @Override public void onServiceDisconnected(ComponentName name) { Log.v("x", "onServiceDisconnected"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onClick(View view) { switch (view.getId()) { case R.id.bindService: { Intent intent = new Intent(this, Service2.class); startService(intent); bindService(intent, conn, Service.BIND_AUTO_CREATE); } break; case R.id.unbindService: { unbindService(conn); } break; case R.id.play: service2.play(); break; case R.id.next: service2.next(); break; case R.id.stop: service2.stop(); break; case R.id.pro: service2.pro(); break; } } }
将Service设置为前台可见
有时候,我们想让Service与用户产生交互,或者给用户提示,我们可以调用public final void startForeground (int id, Notification notification)方法,第一个参数为Notifycation的id,第二个参数为Notifycation对象,在onCreate中调用这个方法,那么Service将会用传入的Notifycation对象,产生一个通知栏提示。可以给与用户提示,onDestroy里面调用stopForeground可以解除前台运行但是不会停止服务,如果在服务被停止的时候,是前台运行状态,通知栏也会一起被清除,不管是否调用了stopForeground。