本篇分为上下两篇,第一篇讲绑定本地服务,第二篇讲使用aidl绑定远程服务。
一、生命周期
注意:
onStart()该方法过时了
服务如果已经开启,就不会重新执行onCreate()方法了。而是会调用
onStart()和onStartCommand()方法
服务停止的时候只执行onDestory()方法
二、绑定服务
使用:Context.bindService()
bindService(intent, conn, Service.BIND_AUTO_CREATE);
参数解释:
第一个:Intent对象
第二个:ServiceConnection对象,创建该对象要实现它的onServiceConnected()和 onServiceDisconnected()来判断连接成功或者是断开连接
第三个:如何创建Service,一般指定绑定的时候自动创建
使用 Context.unbindService(ServiceConnection conn)
解绑即可;
Intent intent = new Intent(this,MyService.class);
//创建绑定的连接
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"bind succeed");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG,"Disconnected");
}
};
bindService(intent,conn, Service.BIND_AUTO_CREATE);
这里呢,我们假设Service是一个领导,你呢,因为工作需要要找领导去批一个大项目,可是领导哪是能随便给你见到的呢?于是就出现一个中间人,这个中间人他可能是领导的朋友,或者跟领导的小舅子的大姨夫的叔叔的隔壁邻居家的狗有点关系。总之呢,他可以见到领导。你想办事的话就只得找他了。
所以我们就定义了一个中间人的变量MiddlePerson,他有个方法,帮你办事。
public class MiddlePerson{
public void handleThings(int money){
if(money > 200){
callLingDao();//请求领导办事
}else{
Toast.makeText(getApplicationContext(),"多准备点钱吧",0).show;
}
}
}
可是我们看到Service中onBind()方法返回的是一个IBinder,我们这个中间人目前还不是IBinder,所以不能返回,因此我们需要把他变一变,我们让他继承IBinder即可,但是继承IBinder会需要你实现好多的方法,不方便。没关系,android已经处理好这个事情了,我们只要再继承Binder就好了,查看源码可以看到他是继承了IBinder类了的,继承Binder类就不需要实现任何方法了。
public class MiddlePerson extends Binder{
public void handleThings(int money){
if(money > 200){
callLingDao();//请求领导办事
}else{
Toast.makeText(getApplicationContext(),"多准备点钱吧",0).show;
}
}
}
好了,我们中间人这个对象算是搞定了,下面给出Service类的全部代码;
Service类:
public class MyService extends Service {
@Override
public void onCreate() {
Log.e(MyService.class.getSimpleName(),"服务被创建了");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(MyService.class.getSimpleName(),"服务启动了");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(MyService.class.getSimpleName(),"服务被销毁了");
super.onDestroy();
}
public class MiddlePerson extends Binder{
public void handleThings(int money){
if(money > 200){
callLingDao();//请求领导办事
}else{
Toast.makeText(getApplicationContext(),"多准备点钱吧",0).show;
}
}
}
public void callLingDao(){
Log.e(MyService.class.getSimpleName(),"项目帮你批好了!");
}
@Override
public IBinder onBind(Intent intent) {
// 返回一个中间人对象
return new MiddlePerson();
}
}
这样呢就可以在之前的连接对象中拿到这个中间人对象了:
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"bind succeed");
//绑定成功后我们就可以拿到中间人对象
Service.MiddlePerson mp = (Service.MiddlePerson)service;
//调用中间人的方法
mp.handleThings(500);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG,"Disconnected");
}
};
以上呢就完成了服务的绑定,并且调用了服务的方法;
优化绑定
但是呢, 我们又想到另外一个问题,中间人和领导间的关系肯定不只有这一个方法,比如中间人还有个陪领导打麻将的方法,
public class MiddlePerson extends Binder{
public void handleThings(int money){
if(money > 200){
callLingDao();//请求领导办事
}else{
Toast.makeText(getApplicationContext(),"多准备点钱吧",0).show;
}
}
public void playMajiang(){
}
}
这个打麻将方法呢,中间人并不想公开,不然随便外面哪个人都可以调用这个方法了。这就影响不好了。
所以最好呢是使用一个接口来暴露这个公开的方法(private方法也有被暴露的可能)。
public interface IMiddlePerson {
void handleThings(int money);
}
然后中间人:
private class MiddlePerson extends Binder implements IMiddlePerson{
@Override
public void handleThings(int money){
if(money > 200){
callLingDao();//请求领导办事
}else{
Toast.makeText(getApplicationContext(),"多准备点钱吧",0).show;
}
}
public void playMajiang(){
}
}
最终Service代码:
public class MyService extends Service {
@Override
public void onCreate() {
Log.e(MyService.class.getSimpleName(),"服务被创建了");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(MyService.class.getSimpleName(),"服务启动了");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(MyService.class.getSimpleName(),"服务被销毁了");
super.onDestroy();
}
private class MiddlePerson extends Binder implements IMiddlePerson {
@Override
public void handleThings(int money) {
if(money > 200){
callLingDao();//请求领导办事
}else{
Toast.makeText(getApplicationContext(),"多准备点钱吧",0).show;
}
}
public void playMajiang(){
}
}
public void callLingDao(){
Log.e(MyService.class.getSimpleName(),"项目帮你批好了!");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MiddlePerson();
}
}
最后在ServiceConnection中修改:
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"bind succeed");
//绑定成功后我们就可以拿到中间人对象
IMiddlePerson myBf = (IMiddlePerson) service;
//调用中间人的方法
mp.handleThings(500);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG,"Disconnected");
}
};
最后我们就是想了完全和服务和中间人都分隔开了,只是暴露了接口。这无疑是最安全的。
注意:
- start服务(保证服务长期在后台运行)
- bind服务(保证调用服务的方法)
- unbind服务
- stopService服务
- 如果先执行1,则服务和activity无关系,activity被销毁服务也不会销毁。
- 如果先执行2,则服务和activity共生死。
- 如果执行顺序1->2,则可保证服务即可在后台长期运行,又可以调用服务的方法。