Android應用程式間通訊之Messenger信使使用及原始碼淺析

yangxi_001發表於2016-12-27

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之間如何選擇方案了。

轉自:http://blog.csdn.net/yanbober/article/details/48373341

相關文章