在Android开发中,有时候我们需要让一个Activity绑定一个Service,进行两者之间的通信。当Activity绑定成功以后,就可以调用Service中的public(或有对应可见级别)的方法。如果Service想把一些信息反馈给Activity,则需要将Activity的Listener传递给Service,由Service负责调用。
这样的做法是可以实现功能的,但有一些缺憾。
首先,Service需要把被调用的方法做成public的,不利于隐藏实现。
第二,调用显得凌乱,在Activity中调用了Service的方法,或者在Service中调用Activity的方法。
所以,developer文档提供了另外一种方式,使用Messenger。API Demos也给出了实现的示例,但该示例没有给出Service如何回应Activity部分的实现,只是给了一段提示性的说明文档:
https://developer.android.com/guide/components/bound-services.html
Notice that this example does not show how the service can respond to the client. If you want the service to respond, you need to also create a Messenger in the client. When the client receives the onServiceConnected() callback, it sends a Message to the service that includes the client's Messenger in the replyTo parameter of the send() method.
根据这个提示,我做了一些实验,走通了Service回应Activity的流程。
Activity与Service之间的通信,无论是Service向Activity发送消息,还是Activity发送消息,都通过Messenger类,这样,Service和Activity就不需要提供public的方法作为通信接口。
首先创建一个工程,实现了如下功能,有一个Activity,上面有三个Button和一个TextView,点击任何一个button,Activity的send messenger就会向Service发送一个message,这个message的replayTo,是Activity的另外一个Messenger, 叫receive messenger。service收到message以后。进行相应的处理,例如生成一个integer,float,string,把处理结果通过receive messenger发送出去,Activity就会收到这个消息。
下面是完整代码,只有3个Class,其他都是AndroidStudio自动生成的。
- MainActivity
-
- public class MainActivity extends AppCompatActivity {
-
- /*
- 标记是否已经绑定Service。
- Marking whether the service has been bound.
- */
- private boolean bServiceConnected;
-
- /*
- 这个Messenger用于向Service发送Message。
- This Messenger is used to send message to service.
- */
- private Messenger mSendMessenger;
-
- /*
- 这个Messenger用于接收服务器发送的Message。
- This Messenger is used to receive message from service.
- */
- private Messenger mReceiveMessenger;
-
-
- private TextView mMessageText;
-
- /*
- 处理从Service收到的Message。
- Handling Messages received from service.
- */
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MessageSource.MSG_CREATE_FLOAT:
- String strI = (String) msg.obj;
- mMessageText.setText(strI);
- break;
- case MessageSource.MSG_CREATE_INT:
- String strF = (String) msg.obj;
- mMessageText.setText(strF);
- break;
- case MessageSource.MSG_CREATE_STRING:
- String strS = (String) msg.obj;
- mMessageText.setText(strS);
- break;
- default:
- break;
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- mMessageText = (TextView) findViewById(R.id.message_from_service);
-
- Button createIntBt = (Button) findViewById(R.id.let_service_create_int);
- createIntBt.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- handleButtonClick(MessageSource.MSG_CREATE_INT);
- }
- });
-
- Button createFloatBt = (Button) findViewById(R.id.let_service_create_float);
- createFloatBt.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- handleButtonClick(MessageSource.MSG_CREATE_FLOAT);
- }
- });
-
- Button createStringBt = (Button) findViewById(R.id.let_service_create_string);
- createStringBt.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- handleButtonClick(MessageSource.MSG_CREATE_STRING);
- }
- });
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (!bServiceConnected) {
- bindService();
- }
-
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- unbindService(mServiceConnection);
- }
-
- private void handleButtonClick(int type) {
- if (bServiceConnected) {
- Message msg = new Message();
- msg.what = type;
- msg.replyTo = mReceiveMessenger;
- try {
- mSendMessenger.send(msg);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- } else {
- Toast.makeText(this, "Service has not been bound.", Toast.LENGTH_SHORT).show();
- }
- }
-
- private void bindService() {
- Intent intent = new Intent(getApplicationContext(), MainService.class);
- bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
- }
-
- private ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
- bServiceConnected = true;
- mSendMessenger = new Messenger(iBinder);
- mReceiveMessenger = new Messenger(mHandler);
- }
-
- @Override
- public void onServiceDisconnected(ComponentName componentName) {
- bServiceConnected = false;
- mSendMessenger = null;
- mReceiveMessenger = null;
- }
- };
- }
- MainService
- public class MainService extends Service {
-
- /*
- 这个Handler负责接收Activity的Message,收到一个Message时,通过获取Message的replayTo得到一个Messenger实例,
- 使用这个Messenger向Activity发送Message。
- This Handler is in charge of receiving Messages sending from Activity. When it receiving a
- Message, get The replayTo which is a Messenger instance from this Message. Using this Messenger
- to send Message to Activity.
- */
- private Handler mActMsgHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MessageSource.MSG_CREATE_INT:
- createAndSendInt(msg.replyTo);
- break;
- case MessageSource.MSG_CREATE_FLOAT:
- createAndSendFloat(msg.replyTo);
- break;
- case MessageSource.MSG_CREATE_STRING:
- createAndSendString(msg.replyTo);
- break;
- default:
-
- break;
- }
- }
- };
-
- /*
- 这个Messenger用于向Activity发送Message。
- This Messenger is used to send Message to Activity.
- */
- private Messenger mSendMessenger = new Messenger(mActMsgHandler);
-
- /*
- 假设有耗时的操作需要异步进行。
- Suppose we have long-running jobs and execute asynchronously.
- */
- private Executor mExecutor = Executors.newCachedThreadPool();
-
- public MainService() {
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mSendMessenger.getBinder();
- }
-
- private void createAndSendInt(final Messenger messenger) {
- mExecutor.execute(new Runnable() {
- @Override
- public void run() {
- Random random = new Random();
- int ret = random.nextInt();
- String str = "Give you a int: " + ret;
- send(MessageSource.MSG_CREATE_INT, str, messenger);
-
- }
- });
- }
-
- private void createAndSendFloat(final Messenger messenger) {
- mExecutor.execute(new Runnable() {
- @Override
- public void run() {
- Random random = new Random();
- float ret = random.nextFloat();
- String str = "Give you a float: " + ret;
- send(MessageSource.MSG_CREATE_FLOAT, str, messenger);
- }
- });
- }
-
- private void createAndSendString(final Messenger messenger) {
- mExecutor.execute(new Runnable() {
- @Override
- public void run() {
- int len = MessageSource.STRING_SOURCE_ARRAY.length;
- Random random = new Random();
- int index = random.nextInt(len);
- String ret = MessageSource.STRING_SOURCE_ARRAY[index];
- String str = "Give you a string: " + ret;
- send(MessageSource.MSG_CREATE_STRING, str, messenger);
- }
- });
- }
-
- private void send(int type, String str, Messenger messenger) {
- Message msg = new Message();
- msg.what = type;
- msg.obj = str;
- try {
- messenger.send(msg);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
还有一个辅助的Class
MessageSource
- public class MessageSource {
- public static final int MSG_CREATE_INT = 1;
- public static final int MSG_CREATE_FLOAT = 2;
- public static final int MSG_CREATE_STRING = 3;
-
- public static final String[] STRING_SOURCE_ARRAY = new String[]{"Awake from dreams",
- "I find the locked tower high",
- "Sober from wine", "I see the curtain hanging low",
- "As last year spring grief seems to grow",
- "Amid the falling blooms alone stand I",
- "In the fine rain a pair of swallows fly",
- "I still remember when I first saw pretty Ping",
- "In silken dress embroidered with two hearts in a ring",
- "Revealing lovesickness by touching pipa’s string",
- "The moon shines bright just as last year",
- "It did see her like a cloud disappear"};
- }
应用截图和操作说明,当点击 CREATE A INTEGER按钮时,Activity就会向Service发送一个Message。
Service收到这个Message以后,根据Message的what,产生了一个Integer,然后把这个integer拼接到一个字符串后面。
创建一个Message,然后用收到的Message的replayTo,发送出去。Activity就收到了Service发来的Message,然后更新TextView里面的内容。