Bound Service 以绑定方式运行的Service

Bound Service 以绑定方式运行的Service

官方:http://developer.android.com/guide/components/bound-services.html
*Service的两种运行方式:*
独立运行:这种运行方式是指Service被其他组件(如Activity)通过调用startService方法启动。由这种方式启动的Service可以保持一直运行,而与启动它的组件的状态无关,即使启动它的组建已经被销毁。通常这种独立启动的Service只需要执行单一的任务,而不必与启动它的组件联系。比如,某个Service可能用来下载或者上传一个文件到网络,当这个任务完成以后,Service就应该销毁自己。(这里的特点就是保证了即使启动它的组件已经被销毁,也能保证任务得到完整执行)
绑定运行:Service除了独立启动去执行单一任务,它也可以被其他组件绑定,通过bindService方法启动运行。绑定启动的Service和绑定它的客户端将拥有一个接口,实现发起请求、获得结果等任务,Service不仅可以在某一应用内被绑定,它还能实现跨进程绑定(IPC),即其他的应用也可以绑定到这个服务。以绑定启动方式运行的Service的生命周期将与和它绑定的组件生命周期相关联,即“非同年同月同日生,但一定同年同月同日同时死”。 一个Service允许同时被多个组件绑定,当所有与它绑定的组件都被销毁时,这个Service也会被销毁。
这里需要注意的是,Service独立运行和绑定运行两种方式并不是互斥的,我们可以同时调用startService和bindService来使这个Service运行起来。
*基础认识*
一个以绑定方式运行的Service是Service抽象类的一个具体实现,并且它允许本应用甚至其他应用的组件绑定到它,并与它交互。一个绑定运行的Service必须实现onBind()方法,这个方法会返回一个IBinder对象,其他组件可以通过Ibinde中的接口与Service实现交互。
当我们调用bindService(Intent intent, ServiceConnection serviceConn, int flags)方法绑定到Service时,intent对象指定了具体绑定的Service类,并可以携带一定的数据,这个intent将会传递给IBinder onBind(Intent)方法,serviceConn对象是接口ServiceConnection的一个实现,它定义了在绑定成功时以及异常断开时的回调方法。当bindService方法调用时,它会立即返回,并不等待连接真正建立;当连接成功创建时,系统会调用ServiceConnection的onServiceConnected (ComponentName name, IBinder binder)方法,其中的binder就包含了客户端与Service之间的接口。 这里需要注意的是,系统仅会在第一次绑定到Service,调用IBinder onBind(Intent)方法,后续的绑定将直接由系统将IBinder对象发送给onServiceConnected (ComponentName name, IBinder binder)方法,而不再调用onBind方法。
当所有绑定到Service的客户端与Service解绑时,系统会自动销毁Service。所以不必我们自己去关闭。
创建一个绑定运行的Service的重点就在于IBinder onBind(Intent)返回的IBinder对象的定义,这里有多种方法,后续将分别介绍。
*创建一个绑定运行的Service*
创建以绑定方式运行的Service可以分为两种应用场景:本地绑定Service、远程绑定Service。
1、本地绑定Service
如果Service只服务于本应用,那么我们只需要继承Binder类,定义我们需要实现的方法即可。具体示例如下:
我们定义这个Service类以及绑定他的客户端类,代码中以注释的形式介绍具体方法:
Service类:

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();
    // Random number generator
    private final Random mGenerator = new Random();
    /**
     内部类,定义了LocalBinder,它提供了一个方法,就是返回所在的Service对象,客户端获得这个对象就可以调用Service类的公开方法     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // 返回所在的Service对象
            return LocalService.this;
        }    }
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    /** method for clients */
    public string getInfo() {
      return "我是LocalService的公开方法,可以通过LocalService对象访问到我";
    }
}

客户端类:

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
       public void onButtonClick(View v) {
        if (mBound) {
            //我们可以通过返回的mService对象调用LocalService的公开方法
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }
    /** 匿名内部类  创建bindService需要的 ServiceConnection 对象*/
    private ServiceConnection mConnection = new ServiceConnection() {
         //当客户端与Service连接成功时,系统会调用这个方法
        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // 将service对象向下转型为LocalBinder对象,LocalService的对象有公共方法getService,这个方法可以获得LocalService对象引用
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

*2、远程绑定Service*
使用Messenger
在这种方式中,我们定义一个Handler来处理不同的Message对象。这个Handler是Messenger实现与客户端共享IBinder的基础,它允许客户端通过Message对象向Service发送命令。另外,客户端也可以定义一个Messenger,这样,Service也可以把消息发送给客户端。 这是实现进程间通信的最简单的方式,因为Messenger队列将会在单线程中执行,我们不需要去考虑线程安全。
使用Messenger实现进程间通信的步骤:

  1. 实现一个Handler,它用来处理传递的Message对象;
  2. 创建一个Messenger对象,将Handler对象作为构造参数;
  3. 使用Messenger对象创建一个IBinder对象,并通过onBind返回;
  4. 客户端将接收到的IBinder对象作为Messenger的构造参数,实例化一个Messenger对象,这个Messenger对象将拥有Handler的引用;
  5. 在客户端通过Handler发送Message对象,Service中就可以通过Handler的handleMessage处理这个Message。
    下面是一个简单的示例:
    Service类:
public class MessengerService extends Service {
    /** Command to the service to display a message */
    static final int MSG_SAY_HELLO = 1;
    /**
     * Handler of incoming messages from clients.
     */
    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();
                    break;
                default:
                    super.handleMessage(msg);
            } }}
    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());
    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

客户端类:

public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;
    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;
    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) return;
        // Create and send a message to the service, using a supported 'what' value
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {//Messenger对象发送消息,这个msg对象将交给Service类中的handleMessage处理
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }
    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

使用AIDL
AIDL (Android Interface Definition Language安卓接口描述语言)。实际上上面介绍的Messenger方式也是基于AIDL实现的,AIDL可以实现对象在进程间的传递。Messenger方式只能一个一个地客户端发送的请求,如果需要同时处理多个请求(多线程),那么可以直接使用AIDL,但是我们必须处理多线程,并且保证线程安全。
官方并不建议使用AIDL,大部分的应用也不必去使用它,AIDL会带来多线程引起的线程安全问题,因此这篇文章中并没对AIDL如何使用做介绍,不过我会另外写文章专门介绍。
*绑定到一个Service:*
应用组件通过bindService绑定到Service.Android系统会调用onBind方法,然后返回一个IBinder给客户端组件,用于和Service交互。
这里的应用组件包括activities, services, and content providers,但不包括broadcast receiver
需要注意的是,绑定过程是异步的,bindService会在调用时立即返回,当真正绑定成功时,系统会通过ServiceConnection返回IBinder对象。
因此,绑定到Service的过程如下:

  1. 实现ServiceConnection接口
    onServiceConnected()方法:当绑定成功时由系统调用,传入IBinder对象
    onServiceDisconnected()方法:当绑定的连接异常关闭时系统会调用这个方法。但是当客户端正常断开连接时,这个方法将不会执行。
  2. 调用bindService方法,将ServiceConnection传入。
  3. 当系统调用onServiceConnected方法时,我们就可以获得IBinder对象。这样我们和Service共享了IBinder对象,IBinder所能引用到的Service内的资源,客户端也就能得到了;
  4. 当需要取消绑定时,调用unBindService()即可。

    当客户端销毁的时候,它会自动取消绑定,但是你仍然应该在不使用Service的时候主动去取消绑定。如果我们需要在Activity可见时,使用这个服务,那么就可以在onStart的时候绑定,而在onStop的时候就取消绑定;如果当Activity进入后台时仍然需要这个服务,那么就在onCreate中绑定,在onDestory中取消绑定。 但是我们不要在onResume中去绑定,在onPause中取消绑定,这样在多个Activity绑定到这个Service时,如果Activity间进行切换,就容易造成冲突。
    一张图认识Bound Service生命周期
    这里写图片描述
    这里需要注意的就是onRebind方法的执行时机。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值