Bound Service

1、绑定式Service在cs结构中扮演着Service的角色,绑定式Service允许其他组件绑定该Service、发送请求、接收相应、甚至IPC通信,绑定式Service通常服务于其他应用程序的组件,且没有明确的后台概念。


2、绑定式Service基础

绑定式Service是一个继承于Service的类,他可以与其他应用交互,为了实现绑定Service,你必须重写onBind()方法,该方法返回一个IBind()借口,此接口是绑定式Service与其他应用组件交互的桥梁。

其他组件可调用bindService()绑定Service,该方法需要传入的参数包含一个实现了ServiceConnection的对象,该对象监控着组件与Service的绑定状态,bindService()并不返回数据,而一旦系统创建了组件与Service的连接,ServiceConnection借口中的方法onServiceConnected()方法会被调用,此时实现了IBinder接口的对象将传递至组件中,这样便实现了Service与绑定组件的通信。

Service可以同时与多个组件绑定,然而Service仅在绑定的第一个组件回调onBind()方法以获得IBinder对象,之后与该Service绑定的组件都传递同一个IBinder对象而不调用onBind()方法。

当Service与绑定他的最后一个组件解绑时,系统将该Service销毁,当然若该Service用start的方法启动过,则不会被销毁。

创建bound Service时,最重要的是实现onBind()方法中的返回接口IBinder,下面将介绍几种不同实现IBinder接口的实现方式。


3、如何实现IBinder接口的方式

(1)继承Binder类:Binder是一个实现了IBinder接口的类,若Service只允许被本应用所在的进程访问(这是大多数情况),你需要继承Binder类,并将给对象作为onBind()方法的返回值,这样与Service绑定的组件就可以通过该返回对象访问Binder的继承类的public方法,甚至是Service中的方法。若在你的应用程序中,Service仅作为一个在后台工作的组件,那么这种方式在好不过了,除非你需要Service进行跨进程通信

(2)使用Messenger:如果需要使用IBinder进行跨进程通信,你应当为Service创建一个Messager对象,这样Service可以定义一个Handler对象以接受不同类型的Message。Handler是Messager的基础,他可以在客户端与IBinder共享,并允许使用Message对象向Service发送指令,除此之外,也可以在client端定义Messenger,这样Service端可以回传信息。

(3)使用AIDL:AIDL是Android接口语言的缩写,大多数应用程序不应该使用AIDL创建bound Service,因为这需要应用程序有处理多线程的能力,而这会使应用程序变得复杂。


4、继承Binder类

若你的Service仅是应用程序内部使用,那么可以继承Binder类,这样,与Service绑定的组件可以直接访问Service中的public方法


请注意:这种继承Binder类的方式仅适用于Service与绑定的组件处在同一个应用程序的情况下。


创建方式:

1)在Service类中创建一个继承于Binder的内部类,在Service类中定义public方法,以便cilent端可以访问,在继承于Binder的内部类中返回该Service实例,将该内部类实例作为onBind()的返回参数。

2)在客户端中的onServiceConnection()回调方法中接收Binder对象,并访问Service的public方法


public class LocalService extends Service {
    //传递给客户端的Binder
    private final IBinder mBinder = new LocalBinder();

    //随机数生成器
    private final Random mGenerator = new Random();

    /**
     * 客户端绑定类,因为我们知道服务总是和绑定的组件运行在同一进程中,我们不需要处理跨进程通信
     */

    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public class LocalBinder extends Binder {
        LocalService getService() {
            //返回一个实例以便我们能够调用服务的方法
            return LocalService.this;
        }

    }

    public int getRandomNumber() {
        return mGenerator.nextInt();
    }
}

在上例中,LocalBinder提供getService()方法来获取LocalService实例,这样客户端就可以通过该实例访问Service中的方法,如下所示


public class MainActivity extends AppCompatActivity {
    LocalService mService;
    boolean mBound = false;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBound = false;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button=new Button(this);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int num = mService.getRandomNumber();
                Log.i("onCreate: ", num + "");
            }
        });
        setContentView(button);
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);



    }

首先,在Activity中的onStart()回调中调用bindService()绑定LocalService(),这时,LocalService中的onCreate()与onBind() 依此回调,接着,ServiceConnection中的onServiceConnection()方法回调,表示组件与Service已经绑定,这时可以通过回传给onServiceConnection()中的IBinder接口对象获得Service的实例,一旦获得该实例,便可以调用Service中的public方法。


请注意:Service应该在合适的时候与组件解除绑定,本例在onStop()中解除绑定


5、使用Messenger绑定Service

当Service需要进行IPC通信时,应当在Service中使用Messenger。使用Messenger方法如下:

1)继承Handle类,并实现回调方法handleMessage()方法,每当cilent端访问Service中的方法时,handleMessager()方法都将回调。

2)需要在Service中创建一个Messenger对象,构造该对象需传入一个Handle参数

3)调用Messenger的getBind()返回一个IBinder对象,将该对象作为onBind()的返回值

4)client端通过onServiceConnection()回传的IBinder参数,构造Messenger对象,并将Message信息传入Messenger对象,发送给Service

5)Service在Handle的handleMessage()方法中接收Message信息

按照这种方式,client并没有显式调用Service中的方法,而是传递Message对象,并在Service中的Hnadle中接收。


以下是Service端示例:

public class MessengerService extends Service {
    static final int MSG_SAY_HELLO = 1;

    //处理从客户端传递过来的消息
    class inComingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello", Toast.LENGTH_SHORT).show();
                default:
                    super.handleMessage(msg);
            }
        }
    }
final Messenger mMessenger=new Messenger(new inComingHandler());
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
}


client客户端

public class ActivityMessenger extends Activity {
    //用来和Service交流的Messenger;
    Messenger mService = null;

    //来表明我们是否绑定了Service
    boolean mBound = false;

    //主页面和服务的交互类
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = new Messenger(service);
            mBound = true;
            Toast.makeText(ActivityMessenger.this, "success", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
            mBound = false;
        }
    };

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
        Button button = new Button(this);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!mBound){
                    Toast.makeText(ActivityMessenger.this, "fail", Toast.LENGTH_SHORT).show();
                    return;
                }
                Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
                try {
                    mService.send(msg);
                } catch (Exception e) {
                    Toast.makeText(ActivityMessenger.this,e.toString(), Toast.LENGTH_SHORT).show();
                }
            }
        });
        setContentView(button);
    }

    @Override
    protected void onStart() {
        super.onStart();

    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        } <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">定Service。</span>


所以,绑定Service有以下步骤:

1)实现ServiceConnection接口:

实现onServiceConnected()方法,当client与Service建立绑定时,系统回调该方法,并将onBind()返回的IBinder参数回传至该方法中

实现onServiceDisconnected()方法,当绑定的Service意外终止时,回调该方法,如进程被kill或者Service崩溃,系统若回调unBindService(),将不会回调onServiceDisconnected()方法。

2)调用bindService,并传入ServiceConnection的实现类对象

3)当系统回调onServiceConnection()时,表示client与Service绑定,此时可以访问Service中的public方法

4)系统回调unbindService(),接触绑定


请注意:当client与Service绑定时,系统destory掉client端,这将破坏绑定状态,好的做法是只要client与Service的交互完成,就解除绑定


其中第三个参数表示绑定的模式,通常为BIND_AUTO_CREATE,表示当Service还尚未处于alive的状态时创建该Service,其他可用参数为BIND_DEBUG_UNBIND,BIND_NOT_FOREGROUND,若不打算制定模式,可传入0


7、需要额外注意的地方

1)当连接错误时,系统会抛出DeadObjectException异常,这也是client端调用Service中的方法时唯一可能抛出的异常。

2)bind和unbind应该成对调用

3)当Activity在前台处于运行状态时,需要与Service绑定,那么应在onStart()中bindService(),在onStop()中unbindService()

4)当Activity在后台处于onStop状态时,那么应该在onCreate()中bindService(),在onDestory()unbindService()

5)不要在onResume()和onPause()方法中绑定、解绑Service,因为这两个生命周期经常被回调,频繁的绑定解绑会降低程序效率


8、管理绑定Service的生命周期

当Service不再与其他任何client绑定时,系统将回收该Service,你无需手动管理,系统会自动管理

若通过两种方式同时启动一个Service,那么如果希望在下一次启动Service绑定client回调onRebind()方法,应该在onUnbind()方法中返回true,按照这种方式,再次与该Service绑定的client仍可以在onServiceConnented()接收到回传的IBinder参数,如下图所示:





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值