首页 > 系统相关 >Android进程间的通信方式

Android进程间的通信方式

时间:2023-04-21 09:57:14浏览次数:71  
标签:val 通信 private fun override 进程 Android null msg

原文地址 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

相关文章

  • 深入理解Android进程间通信机制
    原文地址juejin.cnAndroid系统中有大量IPC(进程间通信)的场景,比如我们想要创建一个新的进程,需要通过Socket这种IPC方式去让ZygoteFork新进程;如果我们要杀掉一个进程,需要通过信号这种IPC方式去将SIGNAL_KILL信号传递到系统内核;如果我们想要唤醒主线程处于休眠中的Looper,需要管道......
  • Android进程间通信总结
    原文地址blog.csdn.netIPCIPC为(Inter-ProcessCommunication)缩写,称为进程间通信或跨进程通信,指两个进程间进行数据交换的过程。安卓中主要采用Binder进行进程间通信,当然也支持其他IPC方式,如:管道,Socket,文件共享,信号量等。Binder简介1.为什么使用Binder?性能方面:......
  • android8 rk3399 同时支持多个USB摄像头
    文章目录一、前文二、CameraHal_Module.h三、CameraHal_Module.cpp四、编译&烧录Image五、App验证一、前文Android系统默认支持2个摄像头,一个前置摄像头,一个后置摄像头需要支持数量更多的摄像头,得修改AndroidHal层的代码二、CameraHal_Module.h修改CAMERAS_SUPPORT_MAX三、Camer......
  • Android问题解决:android.os.FileUriExposedException: file:///storage/......Intent.
    文章目录一、遇到问题二、解决问题三、分析问题一、遇到问题---------beginningofcrash2022-12-2720:18:15.01014422-14422/com.lisi.evidence_boxE/AndroidRuntime:FATALEXCEPTION:mainProcess:com.lisi.evidence_box,PID:14422android.os.FileUriExpose......
  • 整理非系统进程说明
            不定期更新内容进程说明 mDNSResponder.exe 一款名为Bonjour的音乐分享软件相关程序这个进程很多时候是安装了ADOBECS3之后出现的。不过,苹果公司的一些产品(如Safari浏览器)中也捆绑有它,不过在安装前会询问,而且在系统的“添加或者删除程序”中也有卸载入口。......
  • android折线图的实现
    一:配置参考上篇博客二:模板代码MainActivity:publicclassMainActivityextendsAppCompatActivity{privateLineChartmChart;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentVi......
  • 新风格的信号通信
    #include"stdio.h"#include"signal.h"voidsig_handler(intsig){printf("接受到了%d号信号\n",sig);}voidsig_action(intsig,siginfo_t*siginfo,void*restrict_){//sig信号编号//siginfo信号信息//restrict_预留函数......
  • unix domain 与本地本地回环在进程间通信中的差异
    前言:127.0.0.1它是一个私有IP,代表的就是你的本机环回地址,其实本质上是绑定在虚拟网卡loopback上的IP。在实际应用中,有遇到在使用本地回环做进程间通讯的时候程序阻塞的情况。比如下面代码(一)本地回环:客户端数据收发程序:staticintsend_recv(char*cmd,int*ret,char*str......
  • 一种基于Unix Domain和TCP连接的跨设备多进程间通信的方法
    ​前言:在linux系统进程间通信的方式有消息,消息队列,管道,内存映射,套接字等多种方式。在Android系统上进行进程间通信主要是使用Binder,其它的还有共享内存,管道,RPC和UnixDomain等方式。但是,在linux中常用的消息队列,在Android等系统上并不能直接的使用,Android上常用的Binder,在其他......
  • Android安全检测 - 发送隐式广播风险
    这章来学习“发送隐式广播风险”,这个风险和动态注册Receiver风险有呼应之处,可以结合起来一起看。一、漏洞原理隐式广播是指未指定接收方(接收的范围),在发送广播的过程中所有的APP均能够接收到这个广播,那么就会存在广播被拦截的风险,若发送的广播携带数据那么就存在数据泄漏的风险,若......