This article reprints the article, read the original source code can be obtained, at the end of the article has the original link
PS: This article is about using Messenger for inter-process communication. The demo is written in Kotlin
1. Use Messenger
Messenger can be understood as a Messenger, and it can pass Message objects between different processes. Generally, it communicates between the client process and the server process. When we send a Message to the server on the client side, the server Handler will receive the Message from the client side. Then the corresponding processing, after the completion of the processing, and then the results and other data encapsulated into Message, sent to the client, the client’s Handler will receive the processing results.
We do not need to write the AIDL file when we write the Messenger inter-process communication, because Messenger encapsulates AIDL, we do not analyze the source code here, first write the demo, then analyze the source code.
Here’s an example:
(1) to create a new class kotlin MyService and inheritance in the Service, its package name is com. Xe. The demo. Ipcdemo2. Ipcserver:
class MyService: Service() {
var mHandler: MessengerServiceHandler? = null; var TAG: String = "MyService"; var num: Int = 0 var mServiceMesstenger: Messenger? = null; override fun onBind(intent: Intent?) : IBinder { return mServiceMesstenger!! .binder } override fun onCreate() { super.onCreate() mHandler = MessengerServiceHandler() mServiceMesstenger = Messenger(mHandler) } inner class MessengerServiceHandler: Handler() { override fun handleMessage(msg: Message?) { super.handleMessage(msg) if (msg!! .what == 1) { num++ var content: String = msg!! .data.getString("msg") Log.d(TAG,content) var clientMessenger: Messenger = msg.replyTo var message: Message = message.obtain (null,2) var ReplyContent: String = "Send to client" + num + "Message" var bundle: Bundle = Bundle() bundle.putString("replyContent",replyContent) message.setData(bundle); try { clientMessenger.send(message); } catch (e: RemoteException) { e.printStackTrace() } } } } override fun onDestroy() { super.onDestroy() if (mHandler ! = null) { mHandler!! .removeCallbacksAndMessages(null) } }
}
(2) The AndroidManifest.xml file is configured to open multiple processes:
<service android:name=”com.xe.demo.ipcdemo2.ipcserver.MyService”
android:process=":remote">
</service>
(3) to create a new kotlin MainActivity class and inheritance in AppCompatActivity, it package called: com. Xe. Demo. Ipcdemo2. Ipcdemo2
class MainActivity: AppCompatActivity() {
var mTv: TextView? = null var mMyServiceConnection: MyServiceConnection? = null var mMessengerClientHandler: MessengerClientHandler? = null var mClientMesstenger: Messenger? = null var mMessenger: Messenger? = null var num: Int = 0 inner class MyServiceConnection: ServiceConnection { override fun onServiceDisconnected(name: ComponentName?) { } override fun onServiceConnected(name: ComponentName? , service: IBinder?) { mMessenger = Messenger(service) } } inner class MessengerClientHandler: Handler() { override fun handleMessage(msg: Message?) { super.handleMessage(msg) if (msg!! .what == 2) { var fromServiceContent: String = msg.data.getString("replyContent"); mTv!! .setText(fromServiceContent) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mTv = findViewById(R.id.tv); mMyServiceConnection = MyServiceConnection() mMessengerClientHandler = MessengerClientHandler() mClientMesstenger = Messenger(mMessengerClientHandler) bindService() } fun bindService() { var intent: Intent = Intent(this, MyService::class.java) bindService(intent,mMyServiceConnection, Context.BIND_AUTO_CREATE); } fun onClick(v: View) { sendMessage() } fun sendMessage() { num++ var message: Message = Message.obtain(null,1) var bundle: PutCharSequence (" MSG "," this is the "+ num +" message "sent by the client to the server ") message.data = Bundle message.replyTo = mClientMesstenger; try { mMessenger!! .send(message); } catch (e: RemoteException) { e.printStackTrace(); }}
}
Create a new XML file activity_main:
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.xe.demo.ipcdemo2.ipcdemo2.MainActivity"> <Button Android :layout_width="match_parent" android:text=" send message to client "android:onClick="onClick" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv" android:layout_width="match_parent" android:gravity="center" android:layout_height="wrap_content" />
</LinearLayout>
When the program starts to run, the following interface will be displayed:
The picture
After clicking the “Send Message to Client” button, the interface changes as follows:
The picture
The log is then printed as follows:
The picture
To sum up, it is successful to enable multiple processes here. For how to check the process name of multiple processes, you can see the first article on IPC process communication in Android. First of all, the client side of the MainActivity class call bindService (intent, mMyServiceConnection, Context. BIND_AUTO_CREATE) method to start the service, An Intent contains the target service MyService. MMyServiceConnection is an object of type ServiceConnection. MyService’s onBind method returns Messenger’s Binder object after a successful connection. The client’s ServiceConnection implementation class retrieves the callback IBinder object service from the onServiceConnection method. Then use service as parameter to construct a Messenger type object MMessenger, this time MMessenger is the service MyService MMessenger; We also create an object of type Messenger, MClientMesstenger. This MClientMesstenger belongs to the client. When our client sends data to the service using MMessenger, Pass the MClientMesenger over so that the service can use the MClientMesenger to send data to clients.
2, source code analysis
Let’s look at the onBind method for the service MyService
override fun onBind(intent: Intent?) : IBinder {
return mServiceMesstenger!! .binder
}
Point mServiceMesstenger again!!!!! .binder. It calls Messenger’s getBinder method
public IBinder getBinder() {
return mTarget.asBinder();
}
MTarget is the iMessenger interface, constructed from the onCreate method in the MyService we wrote earlier, as shown below
override fun onCreate() {
super.onCreate()
mHandler = MessengerServiceHandler()
mServiceMesstenger = Messenger(mHandler)
}
Click on the Messenger constructor with Handler as the parameter, and you find that the getMessenger method of the Handler object returns
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
Let’s look at the getMessenger method for Handler
final IMessenger getIMessenger() {
synchronized (mQueue) { if (mMessenger ! = null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; }
}
Click on the MessengerImpl class code to read down
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
From IMessenger.Stub you can see that you use AIDL, so MessEnter encapsulates AIDL.
Let’s take a look at how the onServiceConnection method in the implementation class of ServiceConnection on the client gets the MessEnter object
override fun onServiceConnected(name: ComponentName? , service: IBinder?) {
mMessenger = Messenger(service)
}
Click in the constructor of Messenter to see
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
Can be seen from the client here, create a Messenter use IMessenger. Stub. AsInterface (target) to call interface examples, it constructs Messenter use IBinder here as a parameter, Its bottom layer is also implemented by AIDL, where the client MMessEnter and the server MServiceMessenger are not the same object, they can communicate, because they can get the same object Binder.