Android應用程式間通訊之Messenger信使使用及原始碼淺析
1 背景
這個知識點是個low貨,剛開始其實想在之前一篇文章《Android非同步訊息處理機制詳解及原始碼分析》一文中作為一個知識點分析的,但是想了又想又覺得該放在後面程式間通訊分析時再分析。然並卵,還是單獨拿出來寫一篇分析一下吧。
提到Message和Handler其實大家都很熟悉,但是說到Messenger估計有些人還是不太常用的,更有甚者都能把Messenger拼寫錯誤為Messager,以為是Message加了個r,當然,網路上對於Messenger的文章現在也很多了,但是個人分析總結總歸是個人的。哈哈,不扯淡了,言歸正傳。
Messenger實現了IPC通訊,其真實原理也是使用了AIDL進行通訊,但是和直接使用AIDL不同的是Messenger利用了Handler處理通訊,所以它是執行緒安全的(不支援併發處理);而我們平時用的AIDL是非執行緒安全的(支援併發處理)。所以大多數時候我們應用中是不需要處理誇程式併發處理通訊的,所以這時選擇Messenger會比AIDL更加容易操作。
【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流】
2 基礎例項
分析原始碼之前我們先來看一個Demo例子,其核心邏輯就是客戶端程式client傳送一個訊息到服務端程式remote,服務端程式收到訊息後做完處理再回發一個訊息到客戶端client,整個過程採用了Messenger信使和Handler來實現。具體如下:
工程的Android管理檔案:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yanbo.myapplication" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- ":remote"表示在應用程式裡,當需要該service時,會自動建立新的程式
"remote"表示建立全域性程式,不同的應用程式共享該程式 -->
<service android:name=".RemoteService"
android:process=":remote">
<intent-filter>
<action android:name="com.remote.RemoteService"/>
</intent-filter>
</service>
</application>
</manifest>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
工程中的一個獨立程式服務端remote原始碼:
/**
* 另一個程式中的Service
*/
public class RemoteService extends Service {
public static final int MSG_TAG_REMOTE = 0x110;
public static final int MSG_TAG_CLIENT = 0x111;
private Messenger mRemoteMessenger;
private RemoteHandler mRemoteHandler;
private int mCounter = 0;
@Override
public void onCreate() {
super.onCreate();
mRemoteHandler = new RemoteHandler();
//例項化一個Messenger傳入當前Handler
mRemoteMessenger = new Messenger(mRemoteHandler);
}
@Override
public IBinder onBind(Intent intent) {
return (mRemoteMessenger == null) ? null : mRemoteMessenger.getBinder();
}
private class RemoteHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TAG_REMOTE:
//為了把訊息回傳給client端,所以獲取client端設定的Messenger
Messenger clientMessenger = msg.replyTo;
if (clientMessenger != null) {
try {
//注意obtain第一個引數,前面文章有解釋,因為引數target不可序列化
clientMessenger.send(Message.obtain(null, MSG_TAG_CLIENT, ++mCounter, 0));
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
default:
super.handleMessage(msg);
break;
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
工程中的一個獨立程式客戶端client程式碼:
public class MainActivity extends Activity {
private TextView mTextView;
private Messenger mRemoteMessenger = null;
private Messenger mClientMessenger;
private ClientHandler mClientHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.content_show);
//
mClientHandler = new ClientHandler();
mClientMessenger = new Messenger(mClientHandler);
bindService(new Intent(this, RemoteService.class), connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mRemoteMessenger = new Messenger(service);
//注意obtain第一個引數,前面文章有解釋
Message message = Message.obtain(null, RemoteService.MSG_TAG_REMOTE);
message.replyTo = mClientMessenger;
try {
mRemoteMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {}
};
private class ClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case RemoteService.MSG_TAG_CLIENT:
if (mTextView != null) {
mTextView.setText(msg.arg1+"");
}
break;
default:
super.handleMessage(msg);
break;
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
看著了吧,這就是一個超級簡單的Messenger使用場景,具體過程比較形象的描述如下圖:
相信有了這幅圖就不需要再解釋啥了吧,這個也夠明白了。
【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流】
3 Messenger原始碼淺析
通過上面的例項明顯可以看出,在不考慮併發的情況下,Messenger相比AIDL無論從程式碼量、工程結構、複雜度等上都更加勝出一籌。既然這麼好用的東東,那就來看看他的原始碼吧,如下我們先通觀一下Messenger類的整個核心程式碼,然後再細說。如下所示:
/**
* 關聯Handler進行跨程式收發訊息的信使管理橋樑類
* 可以看見Messenger就是一個信使,就是一個Object
*/
public final class Messenger implements Parcelable {
//其實就是遠端的MessengerService的AIDL介面
private final IMessenger mTarget;
//建立一個指向target Handler的Messenger,然後調運Messenger的send就像Handler的sendMessage
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//跨程式傳送訊息,通常用Message.obtain()填充message引數,也可以自己new
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
//獲得Messenger的Binder,一般用在remote端獲取返回
public IBinder getBinder() {
return mTarget.asBinder();
}
//如果兩個Messenger相等則表明指向了相同的Handler
public boolean equals(Object otherObj) {
if (otherObj == null) {
return false;
}
try {
return mTarget.asBinder().equals(((Messenger)otherObj)
.mTarget.asBinder());
} catch (ClassCastException e) {
}
return false;
}
......
//獲取getBinder相同的Messenger物件,一般用在client端獲取
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
通過上面全域性預覽Messenger類及上面的例項使用相信你一定注意到了Messenger有兩個建構函式,分別是public Messenger(Handler target)和public Messenger(IBinder target),很明顯你已經知道了,引數為Handler的是遠端程式例項方法,而引數為IBinder為客戶端程式的例項方法。既然這樣那我們就先從服務端獲取Messenger物件的建構函式public Messenger(Handler target)說起吧,可以看見程式碼如下:
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
- 1
- 2
- 3
- 1
- 2
- 3
該建構函式調運了Handler的getIMessenger方法,這個方法在Handler中原始碼如下:
public class Handler {
......
//其實對於一個Handler物件來說getIMessenger得到的Messenger是一個單例模式物件
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
//單例模式得到Messenger實現類MessengerImpl物件
mMessenger = new MessengerImpl();
return mMessenger;
}
}
//可以看見這其實是Messenger的AIDL實現
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
//send方法真正調運了Handler的sendMessage實現傳送訊息
Handler.this.sendMessage(msg);
}
}
......
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
可以看見,getIMessenger對於每一個Handler物件來說是單例的物件,而且這個IMessenger物件的實現類是MessengerImpl,也可以看見MessengerImpl又是IMessenger.Stub的實現類,這個IMessenger.Stub其實就是AIDL檔案通過aapt自動生成在我們gen或者build目錄下的服務端介面子類而已。那既然這麼說了我們就來確認下吧,看下面這個AIDL檔案(frameworks/base/core/Java/android/os/IMessenger.aidl):
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
//可以看見,上面的MessengerImpl就實現了Messenger遠端的send介面
void send(in Message msg);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
這下明白了吧,Messenger類中的mTarget其實就是一個Handler中單例的IMessenger遠端IPC介面MessengerImpl。
緊接著我們看下Service中的onBind實現,其調運了Messenger的getBinder方法,這個方法原始碼如下:
public IBinder getBinder() {
return mTarget.asBinder();
}
- 1
- 2
- 3
- 1
- 2
- 3
可以看見,其實asBinder返回的就是this,也就是自己,也就是把Service中的Messenger通過onBind方法返回給客戶端。
接著我們暫時回到上面例項的客戶端程式碼,可以發現,客戶端程式首要任務就是通過與遠端程式Service繫結然後獲取遠端Messenger物件例項,其用的建構函式如下:
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
- 1
- 2
- 3
- 1
- 2
- 3
握草,這不就是我們平時獲取服務端物件的實現方法麼?是的,就這樣客戶端就拿到了服務端的Messenger物件,看著好像客戶端新new了一個物件似的,其實不是的。
然後就是傳送過程了,傳送過程的訊息首先是可序列化的,然後通過Messenger的send傳送,而這個send方法上面我們也分析過了,其實現就是通過Handler的sendMessage方法來傳送的,所以不再多解釋,又迴歸到了之前分析的Handler與Message過程。
總體可以發現,其實Messenger沒啥高階的,坦白說其實就是對AIDL的二次封裝後結合Handler讓使用者用起來更加便捷而已。
整個Messenger原理如下:
【工匠若水 http://blog.csdn.net/yanbober 轉載請註明出處。點我開始Android技術交流】
4 Messenger總結
進過分析Messenger後相信已經明白大致是咋回事了,同時也知道編寫AIDL與Messenger之間如何選擇方案了。
相關文章
- Android 程式間通訊 Service、MessengerAndroidMessenger
- Android IPC程式間通訊之AIDL和Messenger的使用AndroidC程式AIMessenger
- Android應用Loaders全面詳解及原始碼淺析Android原始碼
- Android Messenger完全解析 實現程式間通訊AndroidMessenger
- SharedPreferences的使用及原始碼淺析原始碼
- Android 程式之間通訊Android
- Framework 原始碼解析知識梳理(3) 應用程式之間的通訊實現Framework原始碼
- Android中通過Messenger與Service實現程式間雙向通訊AndroidMessenger
- Android應用程式啟動原始碼淺析-(三萬字長文慎點&Android14)Android原始碼
- 【Android原始碼】PackageManagerService 淺析Android原始碼Package
- 【Android原始碼】WindowManagerService 淺析Android原始碼
- Android 熱修復 Tinker 接入及原始碼淺析Android原始碼
- Android 熱修復 Tinker接入及原始碼淺析Android原始碼
- Android桌面Launcher原始碼淺析Android原始碼
- Android 之 Binder與程式間通訊Android
- Android程式間通訊之AIDLAndroidAI
- Android 多程式之Messenger的使用AndroidMessenger
- Android多程式之Messenger的使用AndroidMessenger
- Android的IPC機制(四)—— Messenger的使用及原始碼分析AndroidMessenger原始碼
- Android 使用Socket完成程式間通訊Android
- Flutter 之 InheritWidget 原始碼淺析Flutter原始碼
- android原始碼淺析--AlertControllerAndroid原始碼Controller
- 淺析 及整體分析 Relay 原始碼原始碼
- Android 程式間通訊Android
- 《SharedPreferences的使用及原始碼淺析》讀書筆記原始碼筆記
- Node.js之網路通訊模組淺析Node.js
- Vue響應式原理原始碼淺析Vue原始碼
- webRtc及元件之間通訊Web元件
- Java集合之ConcurrentHashMap原始碼淺析JavaHashMap原始碼
- Android Architecture Component 原始碼淺析Android原始碼
- Gin使用及原始碼簡析原始碼
- Redux原始碼淺析Redux原始碼
- redux 原始碼淺析Redux原始碼
- Koa 原始碼淺析原始碼
- webmagic原始碼淺析Web原始碼
- 淺析Redux原始碼Redux原始碼
- ARouter原始碼淺析原始碼
- Android程式間的通訊Android