原文地址 juejin.cn
前言
在日常的开发中,我们可能会接触到多进程,比如向外界提供服务,或者因为某些原因把某个操作分离到独立的进程执行等等。那么进程与进程之间没办法直接进行数据的传输,也就是我们常说的进程间通信,因此需要借助特定的方案,下面我们一起了解一下几种进程间通信的方案。
正文
1.Intent
平时我们使用Activity、Service跟Receiver的时候,都会用到Intent,Intent里边支持设置Bundle数据,Bundle实现了Parcelable接口,表示它也支持在不同进程间进行传输。所以在不同进程间启动Activity、Service等,我们可以考虑使用Bundle用Intent进行传输,进而达到进程间的通信。
2.使用Messenger
Messenger底层使用的是AIDL,是一种轻量级的跨进程通信方式。Messenger里边用的是一个Handler进行消息处理,消息处理过程是一个队列的形式组织,所以不会存在并发执行。双方的通信主要通过消息的replyTo,拿到对方的Messenger。
下面我们看一个简单的例子:
- 服务端:创建一个Messenger对象,然后使用Handler作为参数,用于处理接收到的消息,并且在service返回messenger对象的binder。
class MessengerService : Service() {
companion object{
const val FROM_CLIENT = 0
const val FROM_SERVICE = 1
}
private val messengerHandler = object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when(msg.what) {
FROM_CLIENT->{
Toast.makeText(applicationContext, msg.data.toString(), Toast.LENGTH_LONG).show()
val client = msg.replyTo
val replayMsg = Message()
replayMsg.what = FROM_SERVICE
val bundle = Bundle()
bundle.putString("key", "msg from service")
replayMsg.data = bundle
client.send(replayMsg)
}
}
}
}
private val messenger = Messenger(messengerHandler)
override fun onBind(intent: Intent?): IBinder? {
return messenger.binder
}
}
复制代码
- 客户端:绑定服务,并且通过Binder去构建一个与服务端通信的Messenger,在发送消息的时候,通过设置replyTo,方便服务端发送消息给到客户端。
class MessengerActivity: AppCompatActivity() {
private val messageHandler = object : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
MessengerService.FROM_CLIENT -> {
Toast.makeText(this@MessengerActivity,
msg.data.getString("key").toString(),
Toast.LENGTH_SHORT
).show()
}
else -> super.handleMessage(msg)
}
}
}
private var serviceMessenger: Messenger? = null
private val clientMessenger = Messenger(messageHandler)
private fun bindService() {
val intent = Intent(this, MessengerService::class.java)
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
private val serviceConnection = object: ServiceConnection{
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
serviceMessenger = Messenger(service)
val msg: Message = Message.obtain(null, MessengerService.FROM_CLIENT)
msg.replyTo = clientMessenger
serviceMessenger?.send(msg)
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
}
复制代码
3.Socket
说到Socket,我们可能会想起TCP/IP的网络模型,还有就是用于网络间传输数据,我们也可以利用其来进行进程间的数据传输实现跨进程通信。
服务端:
class SocketService: Service() {
private val TAG = "TCPServerService"
private var isServiceDestroyed = false
private val mMessages = arrayOf(
"msg 1",
"msg 2",
"msg 3",
"msg 4",
"msg 5",
"msg 6"
)
override fun onCreate() {
Thread(TCPServer()).start()
super.onCreate()
}
override fun onDestroy() {
isServiceDestroyed = true
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
private inner class TCPServer : Runnable {
override fun run() {
var serverSocket: ServerSocket
try {
serverSocket = ServerSocket(8888)
} catch (e: IOException) {
e.printStackTrace()
return
}
while ([email protected]) {
// receive request from client
try {
val client: Socket = serverSocket.accept()
object : Thread() {
override fun run() {
try {
responseClient(client)
} catch (e: IOException) {
e.printStackTrace()
}
}
}.start()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
private fun responseClient(client: Socket) {
//receive message
val inputStreamReader = BufferedReader(
InputStreamReader(client.getInputStream())
)
//send message
val out = PrintWriter(
BufferedWriter(
OutputStreamWriter(
client.getOutputStream()
)
), true
)
out.println("star")
while (!isServiceDestroyed) {
val str: String = inputStreamReader.readLine()
val random = Random()
val index: Int = random.nextInt(mMessages.size)
val msg = mMessages[index]
out.println(msg)
}
out.close()
inputStreamReader.close()
client.close()
}
}
复制代码
客户端:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.tcp_client_activity)
editText = findViewById<View>(R.id.editText) as EditText
textView = findViewById<View>(R.id.displayTextView) as TextView
sendBtn = findViewById<View>(R.id.sendBtn) as Button
sendBtn?.setOnClickListener(this)
sendBtn?.isEnabled = false
stringBuilder = StringBuilder()
val intent = Intent(this@SocketActivity, TCPServerService::class.java)
startService(intent)
object : Thread() {
override fun run() {
connectServer()
}
}.start()
}
private fun connectServer() {
var socket: Socket? = null
while (socket == null) {
try {
socket = Socket("localhost", 8888)
mClientSocket = socket
mPrintWriter = PrintWriter(
BufferedWriter(
OutputStreamWriter(socket.getOutputStream())
), true
)
mHandler.sendEmptyMessage(MSG_READY)
} catch (e: IOException) {
e.printStackTrace()
}
}
// receive message
var bufferedReader: BufferedReader? = null
try {
bufferedReader = BufferedReader(InputStreamReader(socket.getInputStream()))
} catch (e: IOException) {
e.printStackTrace()
}
while (!isFinishing) {
try {
val msg = bufferedReader?.readLine()
if (msg != null) {
val time = System.currentTimeMillis()
val showedMsg = """
server $time:$msg
""".trimIndent()
mHandler.obtainMessage(MSG_RECEIVED, showedMsg).sendToTarget()
}
} catch (e: IOException) {
e.printStackTrace()
}
}
}
复制代码
4.AIDL
AIDL是一种我们比较常用的跨进程通信方案,它能够让我们通过调用定义好的方法,进而实现进程间的通信。
支持的数据类型:
- 基本数据类型
- String、CharSequence
- ArrayList、HashMap,前提是元素类型得被支持
- 实现Parcelable接口
定义好接口:
//##PayInterface.aidl
import com.sendi.account.PaySign;
interface PayInterface {
// AIDL 中除了基本数据类型,其他数据类型必须标上方向,in,out 或者 inout
// in: 输入型参数
// out: 输出型参数
// inout: 输入输出型参数
void pay(in PaySign sign);
}
复制代码
//PaySign.kt
data class PaySign(val sign: String)
//PaySign.aidl
parcelable PaySign;
复制代码
服务端:
class PayService: Service() {
private val mBinder = object: PayInterface.Stub() {
override fun pay(sign: PaySign?) {
//todo: execute pay.
}
}
override fun onBind(p0: Intent?): IBinder {
return mBinder
}
}
复制代码
客户端:
private val mServiceConn: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
payInterface = PayInterface.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName) {}
}
private fun connectPayServer() {
val intent = Intent(this, PayService::class.java)
bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE)
}
private fun startPay() {
try {
//需要放到子线程调用
payInterface?.pay(PaySign("1"))
} catch (e: Exception) {
Log.i("PayClientActivity", "connectPayServer, pay error.")
}
}
复制代码
以上便是AIDL的一个简单例子。
5.ContentProvider
contentProvider用于应用间的数据共享,它是系统对于AIDL的封装,方便我们更快地上手使用。例如日历、通讯录等等。我们也可以自定义ContentProvider,用来操作数据库或者文件中的数据。
ContentProvider定义:
class UserContentProvider: ContentProvider() {
override fun onCreate(): Boolean {
//todo:初始化
}
override fun query(
p0: Uri,
p1: Array<out String>?,
p2: String?,
p3: Array<out String>?,
p4: String?
): Cursor? {
//进行查询
}
override fun getType(p0: Uri): String? {
return null
}
override fun insert(p0: Uri, p1: ContentValues?): Uri? {
//执行数据插入
}
override fun delete(p0: Uri, p1: String?, p2: Array<out String>?): Int {
//执行数据的删除
}
override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array<out String>?): Int {
//执行数据的更新
}
}
复制代码
调用ContentProvider:
//插入数据
fun insert() {
val values = ContentValues()
values.put("_id", 1)
values.put("nickname", "aosendi")
contentResolver.insert(USER_URI, values)
}
//删除数据
fun delete() {
contentResolver.delete(USER_URI, "_id = 1", null)
}
// 更新数据
fun update() {
val values = ContentValues()
values.put("_id", 1)
values.put("nickname", "asd")
contentResolver.update(USER_URI, values, "_id = 1123", null)
}
// 查询数据
fun query() {
val cursor: Cursor? = contentResolver.query(USER_URI, arrayOf("_id", "nickname"), null, null, null)
cursor?.let {
val strBuilder = StringBuilder()
while (cursor.moveToNext()) {
strBuilder.append(cursor.getInt(0))
.append(cursor.getString(1)).append(" ,")
.append("\n")
}
strBuilder.append("------end------------------------")
cursor.close()
}
}
复制代码
监听ContentProvider数据变化:
private fun registerDataChange() {
contentResolver.registerContentObserver(
USER_URI,
true,
object : ContentObserver(mHandler) {
override fun deliverSelfNotifications(): Boolean {
return super.deliverSelfNotifications()
}
override fun onChange(selfChange: Boolean) {
super.onChange(selfChange)
}
override fun onChange(selfChange: Boolean, uri: Uri?) {
Toast.makeText(this@ContentProviderActivity, uri.toString(), Toast.LENGTH_SHORT).show()
super.onChange(selfChange, uri)
}
})
}
复制代码
结语
本文的分享到这里的结束了,相信耐心看到这里的读者,对进程间通信方案有了底,同时也可以根据不同场景,使用合适的方案。
标签:val,通信,private,fun,override,进程,Android,null,msg From: https://www.cnblogs.com/cps666/p/17339255.html