1. 程式人生 > >Android 使用Messenger實現跨app通訊

Android 使用Messenger實現跨app通訊

Android中使用跨程序通訊有以下幾種方式:檔案、廣播、aidl、messenger,今天要講的是使用messenger來實現跨app通訊也就是在兩個不同的app中實現雙向通訊。其實Messenger底層也是使用aidl的方式來實現的,只不過其使用handler來處理訊息,因為handler是執行緒安全的,所以Messenger也是執行緒安全的,自然Messenger只能處理單執行緒的問題,如果要使用多執行緒就該使用aidl的方式實現。

我們來說下通訊的大致流程:首先我們建立兩個應用A、B,在應用B中建立一個Service取名:BService,然後我們在A中通過bindService來繫結BService,這樣之後兩個App就實現了破冰之旅。

上面的情況只是說明了大體的流程,具體如何實現繫結遠端的BService和如何在BService中來回復A應用,這裡我詳細的說下。我們知道bindService()方法中需要三個引數,

bindService(intent, serviceConnection, BIND_AUTO_CREATE);
第一個為Intent物件,第二個為ServiceConnection,最後一個引數為如何去繫結,一般都是寫的這個值。這些相信大家都非常的清楚了,和平時的繫結服務是一樣的,我們做的也是一樣的,不同的是在ServiceConnection中,我們這樣處理返回的IBinder:

     ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                messenger = new Messenger(service);
            }
 
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e("kk", "連結斷開!");
            }
        };
我們看到,這裡我們使用IBinder來建立Messenger物件,然後我們就可以使用這個mesender來像遠端的服務傳送資料:
    Message message = Message.obtain(null, 1);
        Bundle bundle = new Bundle();
        bundle.putString("data", "我要和B說話!");
        message.setData(bundle);
        try {
            messenger.send(message);//傳送資料
        } catch (RemoteException e) {
            e.printStackTrace();
        }
這裡我們使用messenger.send()方法來發送資料。下面我們來看看BService中的程式碼:
public class BService extends Service {
    Messenger messenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    });
 
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("kk", "繫結成功!");
        return messenger.getBinder();
    }
}

這裡我們使用Messenger.getBinder()方法返回IBinder,和A中的程式碼做比較我們就會發現,這裡使用messenger的getBinder()返回IBinder,A中又通過返回的IBinder建立了一個Messenger物件,所以他們都是用的同一個IBinder物件,這樣通過Messenger傳送的訊息自然是會在B中的Messenger建立時候的Handler裡面來處理了,這樣就實現了A像B應用傳送訊息。
那麼B中如何像A傳送訊息呢???我們知道 Message中有屬性:replyTo,該屬性是一個Messenger類別的,如果我們在A類中將該屬性賦值給一個Messenger物件,然後在B類中獲取到該物件然後通過其傳送訊息,這樣訊息自然就會在A類中的Messenger中來處理,這樣就實現了B類向A類傳送訊息,到這裡我們就實現了雙向的通訊,具體修改後的程式碼這裡我貼出來,首先是A類:

message.replyTo = replyMessenger;
essenger replyMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.e("kk", msg.getData().getString("data"));
            super.handleMessage(msg);
        }
    });
然後是在B類中:
public class BService extends Service {
    Messenger messenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.e("kk", msg.getData().getString("data"));
            Message message = Message.obtain();
            Bundle bundle = new Bundle();
            bundle.putString("data","你要說什麼?");
            message.setData(bundle);
            try {
                msg.replyTo.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            super.handleMessage(msg);
        }
    });
 
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("kk", "繫結成功!");
        return messenger.getBinder();
    }
}

我再貼出A類中所有的程式碼:
public class MainActivity extends AppCompatActivity {
    Messenger messenger;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                messenger = new Messenger(service);
            }
 
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e("kk", "連結斷開!");
            }
        };
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.leixinxue.b", "com.example.leixinxue.b.BService"));
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);
    }
 
    public void sendMessageToB(View view) {
        Message message = Message.obtain(null, 1);
        message.replyTo = replyMessenger;
        Bundle bundle = new Bundle();
        bundle.putString("data", "我要和B說話!");
        message.setData(bundle);
        try {
            messenger.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
 
    Messenger replyMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.e("kk", msg.getData().getString("data"));
            super.handleMessage(msg);
        }
    });
}
A類的佈局檔案:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:onClick="sendMessageToB"
        android:text="傳送訊息!" />
</RelativeLayout>


好啦,這裡兩個類就可以實現通訊了,點選A類中的傳送訊息按鈕就可以給B傳送一條訊息,B收到訊息後立馬回覆一個訊息給A。

 

總結:

兩個app間通訊通過Messenger其實很簡單的,就是通過bindService繫結到遠端的service,然後用在繫結的Serviceconnection中返回的IBinder來建立一個Messenger物件,通過Messenger的send傳送訊息到遠端的服務,遠端的服務通過Message中的屬性replyTo就可以回覆收到的訊息,不要忘了給replyTo賦值。好了,詳細我已經將的很詳細了,如果你還有什麼疑問,歡迎給我留言,bye~~