IPC機制之了解Messenger
Messenger翻譯“信使”
在message中放入要跨行程的資料,使用Messenger發送則可以實作跨行程通訊,系統進行了封裝,就不需要自己實作寫aidl了,
實作方式
與傳統的aidl傳輸相同,也是分為客戶端與服務端進行通信,
服務端
服務端主要創建service,同時,以Handler創建Messenger,在service中的onBinder中回傳Messenger中的Binder,
代碼附上:
package com.example.service
import android.app.Service
import android.content.Intent
import android.os.*
import android.util.Log
class MessengerService : Service() {
private class MessengerHandler : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
1 -> {
Log.e(TAG, "handleMessage:收到資訊 :"+msg.data.getString("client_send"))
val clientMessenger = msg.replyTo
val message = Message.obtain(null, 1)
val bundle = Bundle()
bundle.putString("service_send", "來啦!!!")
message.data = bundle
clientMessenger.send(message)
}
2 -> {
}
else -> super.handleMessage(msg)
}
}
}
private val messenger = Messenger(MessengerHandler())
override fun onBind(intent: Intent): IBinder? {
return messenger.binder
}
companion object {
private const val TAG = "MessengerService"
}
}
不用多說,service必須在AndroidManifest.xml中宣告:
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.service.MessengerService"/>
</intent-filter>
</service>
注意:action必須宣告,后續跨行程通信啟動服務要用到, android:enabled=“true”
android:exported="true"也要有,
服務端部署完畢,安裝就行,不啟動依舊可以生效,
客戶端:
客戶端主要啟動服務,將自己的Messenger ,放入發送的message的replyTo 中,這樣,服務器那邊就可以有一個對應的Messenger,發送資訊回來,這樣,就可以來回通信了,實作較為簡單,
package com.example.client
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.*
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private val TAG = "MessengerClient"
lateinit var serviceMessenger: Messenger
var serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceMessenger = Messenger(service)
}
}
var stringBuffer: StringBuffer = StringBuffer()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent()
intent.setPackage("com.example.service")
intent.action = "com.example.service.MessengerService"
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
send_message.setOnClickListener {
val message = Message.obtain(null, 1)
message.replyTo = clientMessenger
val bundle = Bundle()
bundle.putString("client_send", "來啦!老弟!")
message.data = bundle
serviceMessenger.send(message)
stringBuffer.append("Client:來啦!老弟!\n")
all_message.text=stringBuffer
}
}
private val clientMessenger: Messenger = Messenger(@SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message) {
Log.e(TAG, "handleMessage:收到資訊 :" + msg.data.getString("service_send"))
stringBuffer.append("Service:${msg.data.getString("service_send")}\n")
all_message.text=stringBuffer
super.handleMessage(msg)
}
})
override fun onDestroy() {
unbindService(serviceConnection)
val intent = Intent()
intent.setPackage("com.example.service")
intent.action = "com.example.service.MessengerService"
stopService(intent)
super.onDestroy()
}
}
點擊客戶端按鈕,服務端打出日志,并且回復,效果如下:

分析
往下看,可以看到:
messenger本身是實作了parcelable介面


這兩處也可以和aidl相對應;
再看看IMessage介面,
Message引數的定向TAG是in,這說明服務端對Message物件更改,客戶端是不會變化的,
可以參考
IPC機制之了解AIDL(二)定向TAG in out inout的驗證和結論:

結論
- Messenger本質也是AIDL,只是進行了封裝,開發的時候不用再寫.aidl檔案,
- 在service端,Messenger處理client端的請求是單執行緒的,而AIDL是多執行緒的,使用AIDL的時候,service端每收到一個client端的請求時,就會啟動一個執行緒(非主執行緒)去執行相應的操作,而Messenger,service收到的請求是放在Handler的MessageQueue里面,Handler需要系結一個Thread,然后不斷poll message執行相關操作,這個程序是同步執行的,
- 由于Messenger中send方法是的定向TAG是in,因此服務端與客戶端中的資料是異步的,只是將客戶端的資料發送至服務端,服務端更改后對客戶端的資料并不能產生影響,只能使用客戶端通過relayTo傳過來的Messenger將另一個Message發送回去,實作服務端與客戶端的通信,
Messenger小例子(后續附上,代碼其實也不剩啥了,十分簡陋)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/205992.html
標籤:其他
