使用Messenger進行Activity與Service之間的相互通信
在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裏面的內容。
使用Messenger進行Activity與Service之間的相互通信