Service绑定(上)

本篇分为上下两篇,第一篇讲绑定本地服务,第二篇讲使用aidl绑定远程服务。

一、生命周期

Created with Raphaël 2.1.0 onCreate() onStartCommand() onDestory()

注意:
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");
    }
};

最后我们就是想了完全和服务和中间人都分隔开了,只是暴露了接口。这无疑是最安全的。

注意:

  1. start服务(保证服务长期在后台运行)
  2. bind服务(保证调用服务的方法)
  3. unbind服务
  4. stopService服务
    • 如果先执行1,则服务和activity无关系,activity被销毁服务也不会销毁。
    • 如果先执行2,则服务和activity共生死。
    • 如果执行顺序1->2,则可保证服务即可在后台长期运行,又可以调用服务的方法。

猜你喜欢

转载自blog.csdn.net/zzzypp/article/details/66479286