1. 程式人生 > >使用Messenger進行Activity與Service之間的相互通信

使用Messenger進行Activity與Service之間的相互通信

ember hearts 接口 connect sed rst messenger [] ply

在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之間的相互通信