Service--Bound Service

一.基础知识

bound service指的就是 一个继承service的类并且同一其它的应用去绑定它并且和它进行通信。


二.创建Bound Service

当创建一个提供绑定服务的service时,必须提供一个IBinder对象用来和客户端进行通信,有两种提供的方式:

1.Extending the Binder class

如果你的服务只是为你自己的app提供并且和客户端运行在同一个进程中,你应该这么做

(1)创建一个extend Binder的内部类,并且在onBinder()方法中返回该类的实例。

(2)客户端可以获得该Binder对象并且直接调用该类中的方法,甚至直接操作该类所在的Service(继承Binder类的类中实现一个方法,返回Service的实例)。


2.Using a Messenger(implements Parcelable)

如果你希望你的接口作用与不同的进程中,你可以为service创建一个interface通过Messenger的方式进行跨进程通信。在这种方式中,Service会定义一个Handler去回应不同类型的Message实例。

这是最简单的跨进程通信,因为Messager队列中所有的请求都是在仅有的唯一一个进程中的。所以你不需要为了线程安全来设计Service。(因为一次只处理一个请求,其他排队)


3.Using AIDL

AIDL的工作是分解objects变成简单的类型这样操作系统就可以理解并且安排它们横穿过进程,从而完成进程间的通信。之前的教程,通过Messenger的方式进程进程间的通信实际上也是基于AIDLde体系之上的。Messager创造了一个队列,所有客户端的请求都加入唯一的一个队列中,所以Service端一次只能接收一个请求。如果你想要你的Service端同步的处理多个请求,你可以直接使用AIDL。在这个情况下,你的Service要有处理多线程的能力并且可以保证线程安全。



三.几种方式如何使用

1.Extending the Binder class

这方法是应用场景:

client和service在同一个应用中并且在同一个进程中。

使用步骤:

(1)在你的service中创建一个Binder实例

  • 包含public方法,让client可以调用
  • 在public方法中返回Service的实例
  • 或者返回一个可以操作service的寄主对象

(2)在onBinder()方法中返回Binder对象

(3)在client端通过onServiceConnected()回调方法获得Binder实例,并且利用该实例去获得Service的对象


eg:

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();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }

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

    /** method for clients */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}


client端

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;
        }
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute) */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call were something that might hang, then this request should
            // occur in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

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



2.Using a Messenger

这方法是应用场景:

可以不用使用aidl来完成进程间的通信,可以使用Messenger来为Service提供接口。一次只能接收并处理一个请求

使用步骤:

(1)Service中实现一个Handler并实现一个回调函数(handleMessage)用来接收client的每次调用

(2)Handler被用来创造一个Messenger对象

(3)Messenger对象创建出一个IBinder对象,并在onBind中返回该对象

(4)client在onServiceConnection中接收到该IBinder对象,并用它来创建Messenger对象

(5)可以用该Messenger对象来调用sendMessage()方法,将message对象放入Messenger队列中(同一个进程),在Service端的handleMessage中进行接收,从而完成通信

eg:

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();
    }
}




client端:

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 {
            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;
        }
    }
}


注:

这个例子没有展示service端如何回应client端,只是接收客户端的请求而已

如果你想service端做出回应,你需要在client也创建出Messenger对象,


四.一些注意点


1.应该总是抛出DeadObjectException异常,当连接意外中断时会抛出异常。

2.跨进程对象引用计数

3.binding和unbinding要同时使用

  • 如果是在activity中使用,并且activity是visible的。你应该在onStart()中bind,在onStop()中unBind。
  • 如果你想要activity在后台也接收返回结果,应该在onCreate()中bind,在onDestory()中unBind。



五.bound service时生命周期的管理



六.开发过程中遇到的坑





























你可能感兴趣的:(Service--Bound Service)