PS: This article is a reprint of the article, read the original source code can be obtained, at the end of the article there are links to the original
PS: The demo for this article is written in Kotlin
Any operating system, whether Linux or Windows, will have IPC process communication mechanism; Each process is independent of each other, the data between them is not shared, only the data between the same process can be shared; Although each process cannot share data with each other, it can communicate with each other. In Android, IPC inter-process communication is inseparable from Serializable interface, Parcelable interface and Binder. Serializable and Parcelable interface can complete the serialization process of objects. Binder implements the IBinder interface. Binder is a cross-process communication role in Android. Android IPC communication includes using Bundle, using file share, using Messenger, using AIDL, using ContentProvider and using Socket. This post is about using Bundle and Messenger.
1. Use Bundle
The Bundle implements the Parcelable interface, which can communicate between different processes. The Activity, Service, and Receiver can use the Bundle to transfer data between three roles. If we start one of the Activity, Service, or Receiver of another process, The Activity, Service, or Receiver of another process can be transmitted with an Intent by attaching data to the Bundle. The data types that Bundle supports are basic data types, objects that implement the Serializable interface, objects that implement the Parcelable interface, and special objects that can support Android serialization.
Here’s an example:
(1) to create a new MainActivity kt file, its package called com. Xe. Demo. Ipcdemo1. Ipcdemo1
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun onClick(v: If (v.Id == R.IDBtn_1) {var s: String = "IPC interprocess communication using Bundle"; Intent = Intent(this, BundleActivity::class.java) var bundle: Bundle = Bundle() bundle.putCharSequence("key",s) intent.putExtra("bundle",bundle) startActivity(intent) } }
}
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.ipcdemo1.ipcdemo1.MainActivity"> <Button Android :id="@+id/btn_1" android:layout_width="match_parent" android:text=" IPC cross-process communication using Bundle" android:textAllCaps="false" android:onClick="onClick" android:layout_height="wrap_content" />
</LinearLayout>
(3) Create a new BundleActivity file with the package name com.xe.demo.ipcDemo1.ipc
class BundleActivity : AppCompatActivity() {
var mTv: TextView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_bundle) mTv = findViewById(R.id.tv) var bundle: Bundle = intent.getBundleExtra("bundle") var s: CharSequence = bundle.getCharSequence("key") mTv!! .setText(s) }
}
Create a new XML file activity_bundle:
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.ipcdemo1.ipc.BundleActivity">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
(5) Configure the following information in AndroidManifest.xml in order to enable multiple processes:
<activity android:name=”com.xe.demo.ipcdemo1.ipc.BundleActivity”
android:process="com.xe.demo.ipcdemo1.ipc_bundle"></activity>
The interface to start the program is as follows:
The picture
Click the “IPC cross-process communication using Bundle” button to jump to the following interface:
The image shows the data attached from the Bundle in MainActivity. When we open the console, look at the area circled in the image below:
The picture
Will see that there are two process that multiple processes on success, a process is com xe. Demo. Ipcdemo1. Ipcdemo1, was named after the package name to, a process is com xe. Demo. Ipcdemo1. Ipc_bundle, MainActivity is not specified, so running in com. Xe. The demo. Ipcdemo1. Ipcdemo1, BundleActivity specify the process name. Com xe. Demo. Ipcdemo1. Ipc_bundle, So it runs in the com.xe.demo.ipcdemo1.ipc_bundle process.
2. Use file sharing
In Linux, 2 process concurrent read/write file, there’s no limit to exchange data between processes using file, you can store data to a file from a process and then recovering from another process the data, but if the open multi-threaded concurrent read/write files between multiple processes, may be a problem, is data cannot be synchronized; There is no specific file format requirement for cross-process communication using file sharing. SharedPreferences is a special system that uses key-value pairs to store data. The system has a certain cache policy for read/write data. There is a cache of SharedPreferences files in memory. When using multiple processes, it is very likely to lose data in the face of high concurrent read/write access, so it is not recommended to use SharedPreferences.
Here’s an example of using a single thread between multiple processes to read/write files:
(1) Make the following changes to the MainActivity file based on the example “Using Bundle” :
class MainActivity: AppCompatActivity() {
var filePath: String = "/filePath" var myHandler: MyHandler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myHandler = MyHandler() } fun onClick(v: If (v.Id == R.IDBtn_1) {var s: String = "IPC interprocess communication using Bundle"; Intent = Intent(this, BundleActivity::class.java) var bundle: Bundle = Bundle() bundle.putCharSequence("key",s) intent.putExtra("bundle",bundle) startActivity(intent) } else if (v.id == R.id.btn_2) { saveData() } } fun saveData() { Thread(Runnable { var myObject: MyObject = MyObject (" public play programming "small 2, 21) val dir = File (external.getexternalstoragedirectory () getPath () + filePath) if (! dir.exists()) { dir.mkdirs() } val cachedFile = File(Environment.getExternalStorageDirectory().getPath() + filePath + "/my_cache") var objectOutputStream: ObjectOutputStream? = null try { if (! cachedFile.exists()) { cachedFile.createNewFile() } objectOutputStream = ObjectOutputStream(FileOutputStream(cachedFile)) objectOutputStream!! .writeObject(myObject) myHandler!! .sendEmptyMessage(0) } catch (e: IOException) { e.printStackTrace() } finally { try { if (objectOutputStream ! = null) { objectOutputStream!! .close() } } catch (e: Exception) { e.printStackTrace() } } }).start() } inner class MyHandler: Handler() { override fun handleMessage(msg: Message?) { super.handleMessage(msg) [email protected]() } } fun startSharedActivity() { var intent: Intent = Intent(this@MainActivity, SharedActivity::class.java) startActivity(intent) }
}
(2) Modify the activity_main file as follows based on the example “using Bundle” :
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.ipcdemo1.ipcdemo1.MainActivity"> <Button Android :id="@+id/btn_1" android:layout_width="match_parent" android:text=" IPC cross-process communication using Bundle" android:textAllCaps="false" android:onClick="onClick" android:layout_height="wrap_content" /> <Button Android :id="@+id/btn_2" android:layout_width="match_parent" android:text=" Use file share "android:textAllCaps="false" android:onClick="onClick" android:layout_height="wrap_content" />
</LinearLayout>
(3) Create a new KT file MyObject:
class MyObject: Serializable{
var name: String
var age: Int
constructor(name: String,age: Int) {
this.name = name
this.age = age
}
}
Create a new sharedActivity file for KT:
class SharedActivity : AppCompatActivity() {
var myThread: MyThread? = null var myH: MyH? = null var mTv: TextView? = null var filePath: String = "/filePath" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_shared) mTv = findViewById(R.id.tv) myThread = MyThread() myThread!! .start() myH = MyH() } override fun onDestroy() { super.onDestroy() if (myH ! = null) { myH!! .removeCallbacksAndMessages(null) } if (myThread ! = null) { myThread = null } } inner class MyH: Handler() { override fun handleMessage(msg: Message?) { super.handleMessage(msg) var myObject: MyObject = msg!! .obj as MyObject var name: String = myObject.name var age: Int = myObject.age mTv!! .setText(" My name is: ", age is: "+ age)}} inner class MyThread: Thread() { override fun run() { super.run() var cachedFile: File = File(Environment.getExternalStorageDirectory().getPath()+filePath + "/my_cache"); if (cachedFile.exists()) { var objectInputStream: ObjectInputStream? = null; try { objectInputStream = ObjectInputStream(FileInputStream(cachedFile)); var any: Any = objectInputStream!! .readObject(); var message: Message = Message.obtain() message.obj = any myH!! .sendMessage(message) } catch (e: IOException) { e.printStackTrace(); } catch (e: ClassNotFoundException) { e.printStackTrace(); } catch (e: RemoteException) { e.printStackTrace(); } finally { try { if (objectInputStream ! = null) { objectInputStream!! .close(); } } catch (e: Exception) { e.printStackTrace(); } } } } }
}
Create a new XML file activity_shared:
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"
tools:context="com.xe.demo.ipcdemo1.ipc.SharedActivity">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
(6) The AndroidManifest.xml file is configured as follows:
<uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE”></uses-permission>
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”></uses-permission>
<activity android:name=”com.xe.demo.ipcdemo1.ipc.SharedActivity”
android:process="com.xe.demo.ipcdemo1.ipc_bundle"></activity>
The interface to start the application is as follows (some phones have to manually open the APP’s read and write permissions) :
The picture
Click the “Use File Sharing” button to jump to the following interface:
The picture
As can be seen from the text displayed on this interface, we have successfully used file sharing for IPC process communication, and the best way to use file sharing is in a single thread mode. As described in the case “Using Bundle”, how to view a process is not described again here.