ps:本文系转载文章,浏览原文可获取源码,文章开端有原文链接
ps:本文的 demo 是用 Kotlin 语言写的
只有是操作系统,不论是 linux 还是 Windows 零碎,都会有 IPC 过程通信机制;每个过程之间是互相独立的,它们之间的数据是不共享的,只有同一个过程间的数据才共享的;尽管每一个过程之间不能够共享数据,然而能够进行过程之间的通信;在 Android 中 IPC 跨过程通信离不开 Serializable 接口、Parcelable 接口以及 Binder 这 3 个货色,Serializable 和 Parcelable 接口能够实现对象的序列化过程,Binder 实现了 IBinder 接口,Binder 是 Android 中的一种跨过程通信角色;Android IPC 通信的有应用 Bundle、应用文件共享、应用 Messenger、应用 AIDL、应用 ContentProvider 和应用 Socket 这几种形式,这一篇是写应用 Bundle 和 应用 Messenger 这 2 种形式。
1、应用 Bundle
Bundle 实现了 Parcelable 接口,它能够在不同的过程间通信,Activity、Service 和 Receiver 这 3 个角色之间是能够用 Bundle 传输数据的;如果咱们启动了另一个过程的 Activity、Service 和 Receiver 这 3 者中的一个,能够通过 Bundle 中附加数据用 Intent 传送给另一个过程的 Activity、Service 和 Receiver 这 3 者中的一个;Bundle 反对传送的数据类型有 根本数据类型、实现了 Serializable 接口的对象、实现了 Parcelable 接口的对象和可能反对 Android 序列化的非凡对象。
上面咱们举个例子:
(1)新建一个 kt 文件 MainActivity,它的包名为 com.xe.demo.ipcdemo1.ipcdemo1
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun onClick(v: View) {if (v.id == R.id.btn_1) {
var s: String = "应用 Bundle 进行 IPC 跨过程通信"
var intent: Intent = Intent(this, BundleActivity::class.java)
var bundle: Bundle = Bundle()
bundle.putCharSequence("key",s)
intent.putExtra("bundle",bundle)
startActivity(intent)
}
}
}
(2)新建一个 xml 文件 activity_main:
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
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="应用 Bundle 进行 IPC 跨过程通信"
android:textAllCaps="false"
android:onClick="onClick"
android:layout_height="wrap_content" />
</LinearLayout>
(3)新建一个 kt 文件 BundleActivity,它的包名为 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)
}
}
(4)新建一个 xml 文件 activity_bundle:
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
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)在 AndroidManifest.xml 配置一下信息,目标是为了开启多过程:
<activity android:name=”com.xe.demo.ipcdemo1.ipc.BundleActivity”
android:process="com.xe.demo.ipcdemo1.ipc_bundle"></activity>
程序一开始运行的界面如下所示:
图片
点击“应用 Bundle 进行 IPC 跨过程通信”按钮,跳转到如下界面:
图片
这个界面显示的数据,是从 MainActivity 中的 Bundle 附加过去的,当咱们关上控制台的中央,查看如下图圈进去的中央:
图片
就会看到有 2 个过程,阐明多过程开启胜利,一个过程是 com.xe.demo.ipcdemo1.ipcdemo1,是以包名来命名的,一个过程是 com.xe.demo.ipcdemo1.ipc_bundle,MainActivity 没有指定过程,所以运行在 com.xe.demo.ipcdemo1.ipcdemo1,BundleActivity 指定了过程名 com.xe.demo.ipcdemo1.ipc_bundle,所以运行在 com.xe.demo.ipcdemo1.ipc_bundle 过程中。
2、应用文件共享
在 Linux 中,2 个过程并发读 / 写文件是没有限度的,过程之间用文件替换数据,能够从一个过程存储数据到文件中而后从另一个过程中复原这些数据,然而如果多过程之间开启多线程并发读 / 写文件,可能会出问题,就是数据不能同步;应用文件共享这种形式来跨过程通信对文件格式是没有具体要求的,咱们应用的 SharedPreferences 有点特地,它是应用键值对的形式来存储数据,系统对它的读 / 写有肯定的缓存策略,即在内存中会有一份 SharedPreferences 文件的缓存,在应用多过程的时候,面对高并发的读 / 写访问,很有可能失落数据,因而不举荐应用 SharedPreferences。
上面用多过程之间应用单线程读 / 写文件举个例子:
(1)在案例“应用 Bundle”的根底上对 MainActivity 文件做如下批改:
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: View) {if (v.id == R.id.btn_1) {
var s: String = "应用 Bundle 进行 IPC 跨过程通信"
var intent: 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("公众号小二玩编程",21)
val dir = File(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)
this@MainActivity.startSharedActivity()}
}
fun startSharedActivity() {var intent: Intent = Intent(this@MainActivity, SharedActivity::class.java)
startActivity(intent)
}
}
(2)在案例“应用 Bundle”的根底上对 activity_main 文件做如下批改:
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
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="应用 Bundle 进行 IPC 跨过程通信"
android:textAllCaps="false"
android:onClick="onClick"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_2"
android:layout_width="match_parent"
android:text="应用文件共享"
android:textAllCaps="false"
android:onClick="onClick"
android:layout_height="wrap_content" />
</LinearLayout>
(3)新建一个 kt 文件 MyObject:
class MyObject: Serializable{
var name: String
var age: Int
constructor(name: String,age: Int) {
this.name = name
this.age = age
}
}
(4)新建一个 kt 文件 SharedActivity:
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("我的名字叫:" + name + ",年龄是:" + 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();
}
}
}
}
}
}
(5)新建一个 xml 文件 activity_shared:
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
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)AndroidManifest.xml 文件的配置如下所示:
<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>
程序一开始运行的界面如下所示(一些手机要手动关上 APP 的读写权限):
图片
点击“应用文件共享”按钮,跳转到如下界面:
图片
从这个界面显示的文字能够看出,咱们应用文件共享的形式进行 IPC 过程通信胜利,应用文件共享形式最好是在单线程的形式进行;在案例“应用 Bundle”里已形容,查看过程的形式这里不再反复形容。