1. 程式人生 > >Messenger實現多程序通訊

Messenger實現多程序通訊

Messenger進行多程序通訊時一次處理一個請求,在服務端不用考慮執行緒同步的問題,因為服務端不存在併發執行的情況。它的作用主要是為了傳遞訊息,如果需要跨程序呼叫服務端的方法就不適合使用。

用Messenger實現多執行緒通訊時,服務端:

在服務端建立一個Service來處理客戶端的連線請求,同時建立一個Handler並通過這個Handler來建立一個Messenger物件,然後在Service的onBaind方法中返回這個Messenger物件底層的Binder即可。程式碼如下:

public class MessengerService extends Service {
private static final int 
SAY_HOLLE = 0;private static final String TAG = "MessengerService"; private static class MessengerHandler extends Handler{ @Override public void handleMessage(Message msg) { switch(msg.what){ case SAY_HOLLE: Log.e(TAG, "receive msg from client:" + msg.getData().getString("msg"));
break; default: super.handleMessage(msg); } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } }
Service在Android Manifest檔案中的註冊為:
<
service android:name=".MessengerService" android:exported="true" android:enabled="true" android:process=":remote"/>
通過Android Manifest檔案中給Service指定process屬性來實現與客戶端處於不同的程序。

客戶端:

客戶端程序首先要繫結服務端的Service,繫結成功之後用服務端返回的IBinder物件建立一個Messenger,即通過onServiceConnected()方法中的IBinder service引數建立一個客戶端的Messenger物件,然後通過這個Messenger就可以向服務端傳送訊息了,傳送的訊息是Message型別。(新建Message物件,Bundle物件,Bundle物件中放入需要往服務端傳送的訊息內容,然後將Bundle物件放進Message物件中,最後通過Messenger物件將該Message傳送給服務端)程式碼如下圖所示:

public class MainActivity extends AppCompatActivity {
private static final int SAY_HOLLE = 0;private static final String TAG = "MainActivity";
private Messenger mService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
Message msg = Message.obtain(null, SAY_HOLLE,0,0);
Bundle data = new Bundle();
data.putString("msg", "hello, this is client.");
msg.setData(data);try {
mService.send(msg);
            } catch (RemoteException e) {
e.printStackTrace();
            }
        }
@Override
public void onServiceDisconnected(ComponentName name) {
        }
    };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, "onCreate");
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
Log.e(TAG, "onDestroy");
    }
}
這樣就完成了利用Messenger實現程序間通訊的功能。如果需要實現服務端能夠迴應客戶端,那麼客戶端就應該和服務端一樣,需要新建一個Handler,並通過這個Handler新建一個新的Messenger,將這個Messenger物件通過Message的replyTo引數傳遞給服務端,服務端通過這個replyTo引數在服務端新建一個Messenger物件,傳送Message型別的引數就可以迴應客戶端。

實現上述功能客戶端需要新增的程式碼是:

private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case TO_HOLLE:
                Log.e(TAG, "receiver msg from Service:" + msg.getData().getString("reply"));
break;
default:
                super.handleMessage(msg);
        }
    }
}
msg.replyTo = mGetReplyMessenger;

服務端需要新增的程式碼是:

Messenger client = msg.replyTo;
Message replyMessage = Message.obtain(null, TO_HOLLE);
Bundle bundle = new Bundle();
bundle.putString("reply", "嗯, 你的訊息我已經收到, 稍後會回覆你");
replyMessage.setData(bundle);
try {
client.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
服務端總的完整程式碼就是:
/**
 * Created by su on 2017/10/26.
 */
public class MessengerService extends Service {
private static final int SAY_HOLLE = 0;
private static final int TO_HOLLE = 1;
private static final String TAG = "MessengerService";
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case SAY_HOLLE:
                    Log.e(TAG, "receive msg from client:" + msg.getData().getString("msg"));
Messenger client = msg.replyTo;
Message replyMessage = Message.obtain(null, TO_HOLLE);
Bundle bundle = new Bundle();
bundle.putString("reply", "嗯, 你的訊息我已經收到, 稍後會回覆你");
replyMessage.setData(bundle);
try {
client.send(replyMessage);
                    } catch (RemoteException e) {
e.printStackTrace();
                    }
break;
default:
                    super.handleMessage(msg);
            }
        }
    }
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Nullable
    @Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
    }
}
客戶端程式碼是:
public class MainActivity extends AppCompatActivity {
private static final int SAY_HOLLE = 0;
private static final int TO_HOLLE = 1;
private static final String TAG = "MainActivity";
private Messenger mService;
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case TO_HOLLE:
                    Log.e(TAG, "receiver msg from Service:" + msg.getData().getString("reply"));
break;
default:
                    super.handleMessage(msg);
            }
        }
    }
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
Message msg = Message.obtain(null, SAY_HOLLE,0,0);
Bundle data = new Bundle();
data.putString("msg", "hello, this is client.");
msg.setData(data);
//
msg.replyTo = mGetReplyMessenger;
try {
mService.send(msg);
            } catch (RemoteException e) {
e.printStackTrace();
            }
        }
@Override
public void onServiceDisconnected(ComponentName name) {
        }
    };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, "onCreate");
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
Log.e(TAG, "onDestroy");
    }
}
最後在logcat觀察列印輸出的結果時,由於服務端和客戶端在一個應用的不同程序,客戶端在預設的包名程序下,這樣不加設定的話只能看到客戶端的log列印輸出結果,如果要檢視服務端的log列印結果,應該在log上設定過濾器,這樣才能檢視服務端的日誌列印結果。如:

這樣在logcat中觀察服務端列印的資訊就如下圖所示: