Android中的Service小结
简介
Service适合执行不需要和用户交互,而且长期运行的任务。即使程序被切换回后台,服务仍然可以正常运行。Service并不自动开启线程,默认运行在主线程中。
Service中需要重载的函数
onCreate()方法在服务创建的时候调用。onBind()是Service中唯一的抽象方法,必须要在子类中实现。 onStartCommand()在每次启动服务(startService)的时候调用,可用于服务一旦启动就立刻去执行某个动作。
onDestroy()在服务销毁(stopService)的时候调用,可用于收回资源
在Activity中启动和停止服务
可以通过Activity中的Intent来启动/停止Service
Intent startIntent = new Intent(this, MyService.class); startService(startIntent); break; Intent stopIntent = new Intent(this, MyService.class); stopService(stopIntent); break;
在Activity中控制Service
需要创建一个类继承自Binder,然后在里面定义一些处理任务的函数。接着在MyService中创建这个类的实例,并在onBinder中返回。在Activity中创建ServiceConnection匿名类,覆盖onServiceConnected和onServiceDisconnected函数。这两个类在bind和unbind时被调用。
Service的生命周期
在Context中调用startService方法,相应的服务会自动启动,并回调onCreate->onStartCommand 在Context中调用bindService方法,可以获得一个服务的永久链接,并回调onCreate->onBind->onServiceConnected->onUnbind->onServiceDisconnected 销毁的时候不管调用了多少次onStartCommand只会调用一次onDestroy
绑定的Service在被绑定的Activity退出的时候会自动解除绑定。
向Service中传递数据
如果是通过startService启动,在startService的参数Intent中,可以通过putExtra附加数据。在Service端,通过onStartCommand的第一个参数获取这个传过来的值。
如果是通过bindService启动,在Service中的onBind函数会返回一个Binder对象,这个对象会在onServiceConnected中被返回。在Service的Binder对象中定义接口,在Activity中就可以调用。这种通过接口调用的方法要更高效。
从Service中返回数据
1, 在Service中定义callback
2, 在onBind返回的Binder中添加getService函数,让Activity可以取得Service的实例。然后就可以调用Service的setCallBack方法来添加需要通知的函数接口。
跨应用启动Service并传递数据:
在Android5.0之前可以通过隐式intent启动服务,但是Android5.0之后不可以了, 启动Service的Intent必须是Explicit的。
在两个Application之间是不可能获取到Service的定义的,需要调用SetComponent函数:
serviceIntent = new Intent(); serviceIntent.setComponent(new ComponentName("com.wanxiang.www.startservicefromanotherapp", "com.wanxiang.www.startservicefromanotherapp.AppService")); serviceIntent.putExtra("data", "Hello AppService");
通过这种方法可以指定要启动的Service的Application,并且也同样可以传递数据过去。但是有个前提,被启动的这个Service所在的Activity必须在运行过程中的。
同样也可以通过绑定服务来启动远程Service
bindService(new Intent(this, MyService.class), this, BIND_AUTO_CREATE);
本地Activity中的onServiceConnected也会被执行:
@Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { System.out.println("Bind service"); System.out.println(iBinder); }
传递数据:
首先在远程Activity的aidl目录中建一个本地Activity包名的目录,把本地Activity中的AIDL文件拷贝一份过去,可以在onBind()中返回这个接口的stub,并在这个接口中添加函数
@Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return new IAppServiceRemoteBinderInterface.Stub() { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. * * @param anInt * @param aLong * @param aBoolean * @param aFloat * @param aDouble * @param aString */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public void setData(String data) throws RemoteException { AppService.this.data = data; } }; }
在远程Activity中的onServiceConnected函数中返回这个对象,并保存在类的实例变量中:
@Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { System.out.println("Bind service"); System.out.println(iBinder); binder = IAppServiceRemoteBinderInterface.Stub.asInterface(iBinder); } private IAppServiceRemoteBinderInterface binder = null;
然后就可以通过这个变量来调用AIDL中添加的函数,并传递数据给Service。
case R.id.btnSync: if (binder != null) try { binder.setData(etInput.getText().toString());
前台Service
后台的Service会被回收,可以通过在Service中定义Notification,并调用startForeground()来使Service始终保持前台运行。
异步并且自动停止的服务
Android提供了一个IntentService专门解决创建一个异步线程并自动停止的问题。
只需要继承自这个类,并重写onHandleIntent方法,在这个方法里处理一些具体逻辑。这个方法运行在子线程里,不会造成ANR。