在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
1 public class MainActivity extends AppCompatActivity { 2 3 /* 4 标记是否已经绑定Service。 5 Marking whether the service has been bound. 6 */ 7 private boolean bServiceConnected; 8 9 /* 10 这个Messenger用于向Service发送Message。 11 This Messenger is used to send message to service. 12 */ 13 private Messenger mSendMessenger; 14 15 /* 16 这个Messenger用于接收服务器发送的Message。 17 This Messenger is used to receive message from service. 18 */ 19 private Messenger mReceiveMessenger; 20 21 22 private TextView mMessageText; 23 24 /* 25 处理从Service收到的Message。 26 Handling Messages received from service. 27 */ 28 private Handler mHandler = new Handler() { 29 @Override 30 public void handleMessage(Message msg) { 31 switch (msg.what) { 32 case MessageSource.MSG_CREATE_FLOAT: 33 String strI = (String) msg.obj; 34 mMessageText.setText(strI); 35 break; 36 case MessageSource.MSG_CREATE_INT: 37 String strF = (String) msg.obj; 38 mMessageText.setText(strF); 39 break; 40 case MessageSource.MSG_CREATE_STRING: 41 String strS = (String) msg.obj; 42 mMessageText.setText(strS); 43 break; 44 default: 45 break; 46 } 47 } 48 }; 49 50 @Override 51 protected void onCreate(Bundle savedInstanceState) { 52 super.onCreate(savedInstanceState); 53 setContentView(R.layout.activity_main); 54 55 mMessageText = (TextView) findViewById(R.id.message_from_service); 56 57 Button createIntBt = (Button) findViewById(R.id.let_service_create_int); 58 createIntBt.setOnClickListener(new View.OnClickListener() { 59 @Override 60 public void onClick(View view) { 61 handleButtonClick(MessageSource.MSG_CREATE_INT); 62 } 63 }); 64 65 Button createFloatBt = (Button) findViewById(R.id.let_service_create_float); 66 createFloatBt.setOnClickListener(new View.OnClickListener() { 67 @Override 68 public void onClick(View view) { 69 handleButtonClick(MessageSource.MSG_CREATE_FLOAT); 70 } 71 }); 72 73 Button createStringBt = (Button) findViewById(R.id.let_service_create_string); 74 createStringBt.setOnClickListener(new View.OnClickListener() { 75 @Override 76 public void onClick(View view) { 77 handleButtonClick(MessageSource.MSG_CREATE_STRING); 78 } 79 }); 80 } 81 82 @Override 83 protected void onResume() { 84 super.onResume(); 85 if (!bServiceConnected) { 86 bindService(); 87 } 88 89 } 90 91 @Override 92 protected void onPause() { 93 super.onPause(); 94 unbindService(mServiceConnection); 95 } 96 97 private void handleButtonClick(int type) { 98 if (bServiceConnected) { 99 Message msg = new Message(); 100 msg.what = type; 101 msg.replyTo = mReceiveMessenger; 102 try { 103 mSendMessenger.send(msg); 104 } catch (RemoteException e) { 105 e.printStackTrace(); 106 } 107 } else { 108 Toast.makeText(this, "Service has not been bound.", Toast.LENGTH_SHORT).show(); 109 } 110 } 111 112 private void bindService() { 113 Intent intent = new Intent(getApplicationContext(), MainService.class); 114 bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); 115 } 116 117 private ServiceConnection mServiceConnection = new ServiceConnection() { 118 @Override 119 public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 120 bServiceConnected = true; 121 mSendMessenger = new Messenger(iBinder); 122 mReceiveMessenger = new Messenger(mHandler); 123 } 124 125 @Override 126 public void onServiceDisconnected(ComponentName componentName) { 127 bServiceConnected = false; 128 mSendMessenger = null; 129 mReceiveMessenger = null; 130 } 131 }; 132 }
MainService
1 public class MainService extends Service { 2 3 /* 4 这个Handler负责接收Activity的Message,收到一个Message时,通过获取Message的replayTo得到一个Messenger实例, 5 使用这个Messenger向Activity发送Message。 6 This Handler is in charge of receiving Messages sending from Activity. When it receiving a 7 Message, get The replayTo which is a Messenger instance from this Message. Using this Messenger 8 to send Message to Activity. 9 */ 10 private Handler mActMsgHandler = new Handler() { 11 @Override 12 public void handleMessage(Message msg) { 13 switch (msg.what) { 14 case MessageSource.MSG_CREATE_INT: 15 createAndSendInt(msg.replyTo); 16 break; 17 case MessageSource.MSG_CREATE_FLOAT: 18 createAndSendFloat(msg.replyTo); 19 break; 20 case MessageSource.MSG_CREATE_STRING: 21 createAndSendString(msg.replyTo); 22 break; 23 default: 24 25 break; 26 } 27 } 28 }; 29 30 /* 31 这个Messenger用于向Activity发送Message。 32 This Messenger is used to send Message to Activity. 33 */ 34 private Messenger mSendMessenger = new Messenger(mActMsgHandler); 35 36 /* 37 假设有耗时的操作需要异步进行。 38 Suppose we have long-running jobs and execute asynchronously. 39 */ 40 private Executor mExecutor = Executors.newCachedThreadPool(); 41 42 public MainService() { 43 } 44 45 @Override 46 public IBinder onBind(Intent intent) { 47 return mSendMessenger.getBinder(); 48 } 49 50 private void createAndSendInt(final Messenger messenger) { 51 mExecutor.execute(new Runnable() { 52 @Override 53 public void run() { 54 Random random = new Random(); 55 int ret = random.nextInt(); 56 String str = "Give you a int: " + ret; 57 send(MessageSource.MSG_CREATE_INT, str, messenger); 58 59 } 60 }); 61 } 62 63 private void createAndSendFloat(final Messenger messenger) { 64 mExecutor.execute(new Runnable() { 65 @Override 66 public void run() { 67 Random random = new Random(); 68 float ret = random.nextFloat(); 69 String str = "Give you a float: " + ret; 70 send(MessageSource.MSG_CREATE_FLOAT, str, messenger); 71 } 72 }); 73 } 74 75 private void createAndSendString(final Messenger messenger) { 76 mExecutor.execute(new Runnable() { 77 @Override 78 public void run() { 79 int len = MessageSource.STRING_SOURCE_ARRAY.length; 80 Random random = new Random(); 81 int index = random.nextInt(len); 82 String ret = MessageSource.STRING_SOURCE_ARRAY[index]; 83 String str = "Give you a string: " + ret; 84 send(MessageSource.MSG_CREATE_STRING, str, messenger); 85 } 86 }); 87 } 88 89 private void send(int type, String str, Messenger messenger) { 90 Message msg = new Message(); 91 msg.what = type; 92 msg.obj = str; 93 try { 94 messenger.send(msg); 95 } catch (RemoteException e) { 96 e.printStackTrace(); 97 } 98 } 99 }
还有一个辅助的Class
MessageSource
1 public class MessageSource { 2 public static final int MSG_CREATE_INT = 1; 3 public static final int MSG_CREATE_FLOAT = 2; 4 public static final int MSG_CREATE_STRING = 3; 5 6 public static final String[] STRING_SOURCE_ARRAY = new String[]{"Awake from dreams", 7 "I find the locked tower high", 8 "Sober from wine", "I see the curtain hanging low", 9 "As last year spring grief seems to grow", 10 "Amid the falling blooms alone stand I", 11 "In the fine rain a pair of swallows fly", 12 "I still remember when I first saw pretty Ping", 13 "In silken dress embroidered with two hearts in a ring", 14 "Revealing lovesickness by touching pipa’s string", 15 "The moon shines bright just as last year", 16 "It did see her like a cloud disappear"}; 17 }
应用截图和操作说明,当点击 CREATE A INTEGER按钮时,Activity就会向Service发送一个Message。Service收到这个Message以后,根据Message的what,产生了一个Integer,然后把这个integer拼接到一个字符串后面。创建一个Message,然后用收到的Message的replayTo,发送出去。Activity就收到了Service发来的Message,然后更新TextView里面的内容。