Android进程间通信

news2024/12/23 17:42:10

        在操作系统中,每个进程都有一块独立的内存空间。为了保证程序的的安全性,操作系统都会有一套严格的安全机制来禁止进程间的非法访问,但是,很多情况下进程间也是需要相互通信的

进程间通信(Inter-process communication,简称IPC):是指运行在不同进程中的若干线程间的数据交换。

一、使用 Intent 中传递 Bundle 数据

        由于 Bundle 实现了 Parceable 接口,在一个进程中启动另外一个进程的 Activity,Service,Receiver 时,可以很方便的在不同的进程之间进行传输,传输的数据类型必须是基本数据类型或能够被序列化

可以被Bundle传输的数据类型:

  • 基本数据类型(int, long, char, boolean, double等)
  • String 和 CharSequence
  •  ArrayList
  • HashMap
  • 所有实现 Parcelable 接口的对象

代码示例: 

Intent intent = new Intent(MainActivity.this, TwoActivity.class);
Bundle bundle = new Bundle();
bundle.putString("data", "data");
intent.putExtras(bundle);
startActivity(intent);

  总结:

        Bundle进行进程间通信只能进行单方向的简单数据传输,有一定的局限性

二、使用文件共享传输数据

        两个进程通过读/写同一个文件来交换数据,除了交换简单的文本信息之外,还可以序列化一个对象到文件中,来进行数据通信

        文件共享可以是文本文件,也可以是XML文件,读写双方约定数据格式即可

总结:

        使用方便,也是有局限性,并发读写问题,只能适用于数据同步要求不高的进程间通信

三、使用Messenger传输数据

Messenger 是一种轻量级的 IPC 方案,它的底层实现是 AIDL

Messenger的实现

  • 服务端进程:
  1. 在A进程创建一个 Service 来处理其他进程的连接请求
  2. 创建一个 Handler 来创建一个 Messenger 对象
  3. 在 Service 的 onBind() 中返回这个 Messenger 对象底层的 Binder 
public class MessengerService extends Service{
    private Handler messengerHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //取出客户端的消息内容
            Bundle bundle = msg.getData();
            String clientMsg = bundle.getString("client");
            Log.i(TAG, "来自客户端的消息:" + clientMsg);
            //新建一个Message对象,作为回复客户端的对象
            Message message = Message.obtain();
            Bundle bundle1 = new Bundle();
            bundle1.putString("service", "服务端收到");
            message.setData(bundle1);
            try {
                msg.replyTo.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };
    
    //创建服务端Messenger
    private final Messenger mMessenger = new Messenger(messengerHandler);
        
    @Override
    public IBinder onBind(Intent intent) {
        //向客户端返回IBinder对象,客户端利用该对象访问服务端
        return mMessenger.getBinder();
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
    }
}
  • 客户端进程:
  1. 在进程B中绑定远程进程 Service
  2. 绑定成功后,根据 Service 返回的 IBinder 对象创建 Messenger 对象,并使用此对象发送消息
  3. 客户端创建了一个 Messenger 发送给 Service 端,Service 端就可以通过客户端的 Messenger 向客户端发送消息
public class MessengerActivity extends Activity{  
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取服务端关联的Messenger对象
            Messenger mService = new Messenger(service);
            //创建Message对象
            Message message = Message.obtain();
            Bundle bundle = new Bundle();
            bundle.putString("client", "服务端在吗,听到请回答");
            message.setData(bundle);
            //在message中添加一个回复mReplyMessenger对象
            message.replyTo = mReplyMessenger;
            try {
                mService.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    //为了收到Service的回复,客户端需要创建一个接收消息的Messenger和Handler  
    private Handler messengerHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //消息处理
            Bundle bundle = msg.getData();
            String serviceMsg = bundle.getString("service");
            Log.i(TAG, "来自服务端的回复:" + serviceMsg);
        }
    };

    private Messenger mReplyMessenger = new Messenger(messengerHandler);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);
        init();
    }

    private void init() {
        Intent intent = new Intent(MessengerActivity.this, MessengerService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        unbindService(conn);
        super.onDestroy();
    }
} 

总结:

        使用 Handler 实现,以串行的方式处理客服端发送过来的消息,只能适用于并发小的消息传递

四、使用AIDL传递数据

 AIDL的原理

         使用了代理模式对Binder的使用进行了优化,使用AIDL保证了代码的整洁,省去了编写繁琐的代理类相关代码。

实现步骤:

  • 1.创建AIDL接口

    • 在要创建AIDL的目录上右键->New->AIDL->AIDl File 来创建一个AIDL文件

    • 创建一个名为IXXXService的AIDL文件,并添加一个getxxx的方法

    • Rebuild一下项目,IDE会自动生成AIDL的代码

  • 2.AIDL生成的代码

    • 在项目的build同包名目录下,自动生成的一个名为IXXXService的接口

    • 在接口中有一个名为Stub的内部类,它继承了Binder,并实现了IXXXService接口,它的内部有一个asInterface的方法

    • Stub类中还有一个名为Proxy的内部类,Proxy的getxxx方法通过Binder去读取服务端的写入数据。

  • 3.AIDL客户端

    • 连接到服务端后通过IXXXService.Stub下的asInterface方法来获取Binder或者Binder的代理对象

示例代码:

        1.编写aidl类    

// IMyAidlInterface.aidl
package com.lf.hilibrary.aidl;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    String getname(String name);
}

        2.项目build生成java文件

 

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.lf.hilibrary.aidl;
// Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface
{
  /** Default implementation for IMyAidlInterface. */
  public static class Default implements com.lf.hilibrary.aidl.IMyAidlInterface
  {
    /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
    {
    }
    @Override public java.lang.String getname(java.lang.String name) throws android.os.RemoteException
    {
      return null;
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.lf.hilibrary.aidl.IMyAidlInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.lf.hilibrary.aidl.IMyAidlInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.lf.hilibrary.aidl.IMyAidlInterface interface,
     * generating a proxy if needed.
     */
    public static com.lf.hilibrary.aidl.IMyAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.lf.hilibrary.aidl.IMyAidlInterface))) {
        return ((com.lf.hilibrary.aidl.IMyAidlInterface)iin);
      }
      return new com.lf.hilibrary.aidl.IMyAidlInterface.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_basicTypes:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          long _arg1;
          _arg1 = data.readLong();
          boolean _arg2;
          _arg2 = (0!=data.readInt());
          float _arg3;
          _arg3 = data.readFloat();
          double _arg4;
          _arg4 = data.readDouble();
          java.lang.String _arg5;
          _arg5 = data.readString();
          this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_getname:
        {
          data.enforceInterface(descriptor);
          java.lang.String _arg0;
          _arg0 = data.readString();
          java.lang.String _result = this.getname(_arg0);
          reply.writeNoException();
          reply.writeString(_result);
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.lf.hilibrary.aidl.IMyAidlInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      /**
           * Demonstrates some basic types that you can use as parameters
           * and return values in AIDL.
           */
      @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(anInt);
          _data.writeLong(aLong);
          _data.writeInt(((aBoolean)?(1):(0)));
          _data.writeFloat(aFloat);
          _data.writeDouble(aDouble);
          _data.writeString(aString);
          boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public java.lang.String getname(java.lang.String name) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.lang.String _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeString(name);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getname, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getname(name);
          }
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      public static com.lf.hilibrary.aidl.IMyAidlInterface sDefaultImpl;
    }
    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getname = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    public static boolean setDefaultImpl(com.lf.hilibrary.aidl.IMyAidlInterface impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.lf.hilibrary.aidl.IMyAidlInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
  public java.lang.String getname(java.lang.String name) throws android.os.RemoteException;
}

3.客户端调用

public class AidlActivity extends AppCompatActivity {

    private IMyAidlInterface mProxy;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bindService();

//        btn.setOnClickListener(view -> getName("lf"));
    }

    // 绑定服务
    private void bindService() {
        String action = "android.intent.action.server.aidl.gradeservice";
        Intent intent = new Intent(action);
        intent.setPackage(getPackageName());
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    }

    // 查询成绩
    private void getName(String name) {
        String result;
        try {
            result = mProxy.getname(name);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 连接服务后,根据是否跨进程获取Binder或者Binder的代理对象
            mProxy = IMyAidlInterface.Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mProxy = null;
        }
    };
}

五、使用ContentProvider的方式传递数据

        应用程序通过ContentProvider 暴露数据操作的接口,其他应用程序通过接口来操作接口内的数据,包括数据的增、删、改、查等操作。

        ContentProvider 分为系统的(如:联系人,图片等),和自定义的

自定义ContentProvider

  1. 定义ContentProvider 类,继承 ContentProvider 基类
  2. 在 AndroidMainfest.xml 中注册ContentProvider,给 ContentProvider 绑定一个域名
  3. 其他应用就可以访问 ContentProvider 暴露出来的数据了
    1. 调用 Activity 的 getContentResolver() 获取 ContentResolver 对象;
    2. 根据调用的 ContentResolver 的 insert()、delete()、update() 和 query() 方法操作数据库即可。

六、使用BroadcastReceiver的方式

        通过广播来实现跨进程通信

实现方式:

  1. 创建需要启动的 BroadcastReceivert 的 intent;
  2. 调用 Context 的 sendBroadcast() 或者 sendOrderBroadcast() 方法来启动指定的 BroadcastReceivert。

七、使用 Socket 的方式

        通过网络通信来实现跨进程通信

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/445607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式学习笔记——SPI通信的应用

SPI通信的应用 前言屏幕分类1.3OLED概述驱动芯片框图原理图通信时序显示的方式页地址、列地址初始化指令 程序设计初始化代码初始化写数据与写命令清屏函数 初始化代码字符显示函数 总结 前言 上一篇中介绍了STM32的SPI通信,并根据框图和寄存器进行了SPI通信的初始…

轻松掌握k8s(使用docker)安装知识点

1、介绍 kubernetes具有以下特性: 服务发现和负载均衡 Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器,如果进入容器的流量很大, Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。存储编排 Kubernetes 允许你自…

【数据库】— 无损连接、Chase算法、保持函数依赖

【数据库】— 无损连接、Chase算法 Chase算法Chase算法举例一种简便方法:分解为两个模式时无损连接和函数依赖的一个简单例子 Chase算法 形式化定义: 构造一个 k k k行 n n n列的表格,每行对应一个模式 R i ( 1 ≤ i ≤ k ) Ri (1≤i ≤ k)…

计算机组成原理汇总

提示:日落归山海,山海藏深情 文章目录 1.1 计算机的发展1.2 计算机硬件的基本组成1.3 计算机的性能指标2.1.1 进位计数制2.1.2 BCD码2.1.3 无符号整数的表示和运算2.1.4 带符号整数的表示和运算(原反补)2.1.5原反补码的特性对比2.1.6 移码2.1.7 定点小数…

【逗老师的无线电】骚活,GPS热点盒子自动上报APRS位置

逗老师最近整了个有意思的小活,组装了一个有4G网卡带GPS功能的热点盒子,让盒子基于GPS位置信息,自动上报APRS位置帧 全篇亮点 基于GPS和AGPS共同定位基于TCP直接上报APRS数据帧 别说,这小活整完之后,还是有点意思的&…

linux coredump

文章目录 是什么生成原理coredump 的“危害” reference: 一文读懂Coredump文件是如何生成的 GDB是什么? 是什么 简单的讲:当进程接收到某些信号而导致异常退出时,就会生成 coredump 文件 在程序发生某些错误而导致进程异常退出时&#x…

技术分析内核并发消杀器(KCSAN)一文解决!

一、KCSAN介绍 KCSAN(Kernel Concurrency Sanitizer)是一种动态竞态检测器,它依赖于编译时插装,并使用基于观察点的采样方法来检测竞态,其主要目的是检测数据竞争。 KCSAN是一种检测LKMM(Linux内核内存一致性模型)定义的数据竞争(data race…

亿发软件:中大型仓库进出货管理系统解决方案,定制软件让仓储作业高效便捷

中大型仓库出入库管理是传统厂家供应链管理流程的重要部分,直接关乎货物在仓库当中存储的安全,和员工工作的效率。一旦仓库管理当中出现了疏漏,那么货物的信息数据就会发生变动,导致实际与账目不符。人工带来的低效与不可控是传统…

软件测试行业到底有没有前景和出路?

我现在来跟你说说软件测试的真正情况。 首先一个软件做出来,最不能少的人是谁?不用说就是开发,因为开发是最了解软件运作的那个人,早期不少一人撸网站或者APP的例子,相当于一个人同时是产品、研发、测试、运维等等&am…

15-721 Chapter9 数据压缩

Background disk database的瓶颈在disk IO上的话(也就是说数据压缩的好处很大,可以比较放心的做),那么内存数据库的瓶颈是多方面的,其中包含cpu。所以我们要在计算量和压缩率(DRAM还是有点贵的&#xff0c…

需求管理实践四大流程的注意事项

需求管理实践包括四大流程:需求采集、需求分析、需求筛选和需求处理。 1、需求采集注意事项 需求采集需要通过多种形式对不同用户需求进行收集,并对需求的属性进行详细记录,并记录可追溯的反馈人员,以便后期跟踪修改。 需求管理实…

你不知道的Redis Search 以及安装指南

theme: orange 本文正在参加「金石计划」 这篇文章是为了使用Redis Search 的向量搜索功能提前做的环境准备工作。即讨论如何在准备生产的 linux 环境中安装 RediSearch 和 RedisJSON 模块。 什么是RediSearch? 根据RediSearch的官方文档 RediSearch是这样描述的。 …

线性表,栈和队列(2)

作者:额~我那个早过50了,忘记了 言归正传ca 什么是栈? 小李攒钱买了车,可是他家住在胡同的尽头。胡同很窄,只能通过一辆车,而且是死胡同。小李每天都为停车发愁,如果回家早了停在里面&#x…

pandas笔记:pandas 排序 (sort_values)

1 函数说明 DataFrame.sort_values(by,*, axis0, ascendingTrue, inplaceFalse, kindquicksort, na_positionlast, ignore_indexFalse, keyNone) 2 参数说明 by string或者一组string组成的list,根据什么进行排序 axis{0 or ‘index’, 1 or ‘columns’}ascendi…

其它 Composition API

1.shallowReactive 与 shallowRef shallow有浅的意思 首先在原有的页面上引入它,然后用shallowReactive包裹它 浅层次的意思就是像name,age这些是响应式的,而job就不处理,意思就是只处理第一层数据,像第二层的都不处理…

电气互联系统有功-无功协同优化模型

目录 1 主要内容 模型示意图 目标函数 程序亮点 2 部分程序 3 程序结果 4 程序链接 1 主要内容 本程序基本复现《“碳中和”目标下电气互联系统有功-无功协同优化模型》,文献模型提供了一个很好的创新思路,把常规电气互联系统的调度和有功无功优化…

【Linux】-关于Linux的指令(上)

作者:小树苗渴望变成参天大树 作者宣言:认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! TOC 前言 今天我们来讲关于Linux的基本指令,博主讲的指令会对应着Windows…

Java 8中新特性Stream的详细理解和使用

Java 8中新特性Stream的基本理解和使用 Stream基本概念 Stream流是来自数据源的元素队列并支持聚合操作 **元素:**是特定类型的对象,是数据源形成的一个队列。Java中Stream不会存储元素,而是按需计算 数据源:Stream流数据的来…

自定义函数 | R语言批量计算组间差值

批量字符替换、数值大小比较并重新赋值 cal_repeat()函数的实际操作1.不考虑处理变量。考虑多变量和指定2列变量的情况(长数据):2.考虑处理变量。考虑多处理,多变量的情况(长数据):3.考虑处理变…

Node【Global全局对象】

文章目录 🌟前言🌟Global全局对象🌟Global对象属性与方法🌟Global对象属性🌟process🌟Buffer类🌟console 🌟写在最后 🌟前言 哈喽小伙伴们,新的专栏 Node 已…