Skip to content

天楚锐齿

人工智能 云计算 大数据 物联网 IT 通信 嵌入式

天楚锐齿

  • 下载
  • 物联网
  • 云计算
  • 大数据
  • 人工智能
  • Linux&Android
  • 网络
  • 通信
  • 嵌入式
  • 杂七杂八

Android使用Messenger和SharedMemory实现跨app的海量数据传输

2022-04-20
    Messenger是android下轻量级的跨进程通信机制,SharedMemory可以作为Messenger中Message的Bundle数据来发送,从而实现海量数据传输。

一、直接使用SharedMemory方式

Server端:
下面为MessengerService类的代码,在MainActivity里面把它启动即可,也可以客户端app通过bindservice来拉起它:
package com.maxshu.messenger_sharedmemory;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.SharedMemory;
import android.system.ErrnoException;
import android.util.Log;
import java.nio.ByteBuffer;
import androidx.core.app.NotificationCompat;
public class MessengerService extends Service {
private static final String TAG = “MessengerService”;
private MessengerHandler mHandler=new MessengerHandler();
private Messenger mMessenger=new Messenger(mHandler);
public MessengerService() {
Log.i(TAG,”MessengerService().”);
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,”onBind().”);
return mMessenger.getBinder();
}
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//取出客户端的消息内容
Bundle bundle = msg.getData();
String clientMsg = bundle.getString(“client”);
Log.i(TAG,”来自客户端的消息:”+clientMsg);
//通过SharedMemory共享内存得到的数据
int sharedMemoryLen = bundle.getInt(“sharedmemory_len”);
SharedMemory sharedMemory = bundle.getParcelable(“sharedmemory_data”);
if (sharedMemory == null) {
Log.i(TAG,”sharedMemory为空。”);
return;
}
try {
ByteBuffer byteBuffer = sharedMemory.mapReadOnly();
int len = byteBuffer.limit() – byteBuffer.position();
Log.i(TAG, “sharedMemory: len:” + len);
byte[] bytes = new byte[sharedMemoryLen];
byteBuffer.get(bytes);
Log.i(TAG, “sharedMemory: bytes[0]:” + bytes[0]);
Log.i(TAG, “sharedMemory: bytes[0]:” + bytes[1]);
Log.i(TAG, “sharedMemory: bytes[sharedMemoryLen-2]:” + bytes[sharedMemoryLen – 2]);
Log.i(TAG, “sharedMemory: bytes[sharedMemoryLen-1]:” + bytes[sharedMemoryLen – 1]);
Log.i(TAG, “sharedMemory: bytes.length:” + bytes.length);
Log.i(TAG, “sharedMemory: sharedMemory:” + sharedMemory.toString());
Log.i(TAG, “sharedMemory: sharedMemory.size:” + sharedMemory.getSize());
//使用完unmap同时close sharedMemory释放内存
SharedMemory.unmap(byteBuffer);
sharedMemory.close(); //对端create,本端使用完close.
}catch (ErrnoException e){
Log.i(TAG, “sharedMemory错误:”);
e.printStackTrace();
return ;
}
//新建一个Message对象,作为回复客户端的对象
Message message = Message.obtain();
Bundle bundle1 = new Bundle();
bundle1.putString(“service”,”今天就不去了,还有很多东西要学!!”);
message.setData(bundle1);
try {
msg.replyTo.send(message);
Log.i(TAG,”发送消息到客户端。”);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onCreate() {
Log.i(TAG,”onCreate().”);
super.onCreate();
startForeground();
}
private void startForeground() {
Log.i(TAG,”startForeground().”);
String CHANNEL_ONE_ID = “com.maxshu.messenger_sharedmemory.channel”;
String CHANNEL_ONE_NAME = “Channel One”;
NotificationChannel notificationChannel = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(notificationChannel);
startForeground(1, new NotificationCompat.Builder(this, CHANNEL_ONE_ID).build());
}
}
}
Server端的AndroidManifest.xml:
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android“
package=”com.maxshu.messenger_sharedmemory”>
<uses-permission android:name=”android.permission.FOREGROUND_SERVICE”/>
<application
android:allowBackup=”true”
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:roundIcon=”@mipmap/ic_launcher_round”
android:supportsRtl=”true”
android:theme=”@style/Theme.Messenger_SharedMemory”>
<service
android:name=”.MessengerService”
android:enabled=”true”
android:exported=”true”>
<intent-filter>
<action android:name=”android.intent.action.MESSENGER” />
</intent-filter>
</service>
<activity
android:name=”.MainActivity”
android:exported=”true”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>
</manifest>
Client端:
client端通过bindservice调用服务端代码即可:
package com.maxshu.messenger_sharedmemory_2;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.SharedMemory;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.util.Log;
import java.nio.ByteBuffer;
public class MainActivity extends AppCompatActivity {
private static final String TAG = “MainActivity”;
private Messenger mService;
private GetRelyHandler mGetRelyHandler = new GetRelyHandler();
private Messenger mRelyMessenger = new Messenger(mGetRelyHandler);
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, “onServiceConnected.”);
//获取服务端关联的Messenger对象
mService = new Messenger(service);
//创建Message对象
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString(“client”, “今天出去玩吗?”);
//使用SharedMemory共享内存来跨app进程传输大量数据
byte[] bytes = new byte[1024*1024*4]; //4MB
bytes[0] = ‘a’;
bytes[1] = ‘5’;
bytes[1024*1024*4-2] = ‘5’;
bytes[1024*1024*4-1] = ‘a’;
try {
SharedMemory sharedMemory = SharedMemory.create(“sharedmemory”, bytes.length);
ByteBuffer buffer = sharedMemory.mapReadWrite();
buffer.put(bytes);
//把sharedMemory权限设置为只读,create默认是读写权限都有,这里可以避免客户端更改数据
sharedMemory.setProtect(OsConstants.PROT_READ);
//使用完需要unmap
SharedMemory.unmap(buffer);
bundle.putInt(“sharedmemory_len”, bytes.length);
bundle.putParcelable(“sharedmemory_data”, sharedMemory);
Log.i(TAG, “sharedMemory: bytes.length:”+bytes.length);
Log.i(TAG, “sharedMemory: sharedMemory:”+sharedMemory.toString());
Log.i(TAG, “sharedMemory: sharedMemory.size:”+sharedMemory.getSize());
}catch (ErrnoException e){
Log.i(TAG, “sharedMemory错误:”);
e.printStackTrace();
return;
}
//设置数据内容
message.setData(bundle);
//在message中添加一个回复mRelyMessenger对象
message.replyTo = mRelyMessenger;
try {
mService.send(message);
Log.i(TAG, “发送消息到服务器端。”);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, “onServiceDisconnected.”);
mService = null;
}
};
public static class GetRelyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String serviceMsg = bundle.getString(“service”);
Log.i(TAG, “来自服务端的回复:” + serviceMsg);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//启动服务端的MessengerService
Intent intent = new Intent();
//和服务端AndroidManifest.xml的MessengerServiceService的intent-filter的Action name保持一致:
intent.setAction(“android.intent.action.MESSENGER”);
intent.setPackage(“com.maxshu.messenger_sharedmemory”); //服务端的包名
//启动服务,如果服务端Service没有启动,则自动拉起
boolean rtn = bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
if(rtn){
Log.i(TAG, “启动服务端MessengerService成功。”);
}else {
Log.i(TAG, “启动服务端MessengerService失败。”);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销绑定
unbindService(mConnection);
}
}
Client端的AndroidManifest.xml:
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android“
package=”com.maxshu.messenger_sharedmemory_2″>
<!–Android11之后,必须加入该queries条目,才能拉起其他app的Service –>
<queries>
<package android:name=”com.maxshu.messenger_sharedmemory” />
</queries>
<application
android:allowBackup=”true”
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:roundIcon=”@mipmap/ic_launcher_round”
android:supportsRtl=”true”
android:theme=”@style/Theme.Messenger_SharedMemory”>
<activity
android:name=”.MainActivity”
android:exported=”true”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>
</manifest>

二、间接使用Binder方式(底层实现也是用的共享内存方式)

    使用Binder调用传图,是往Intent里塞了个Binder对象,等到另一个组件启动之后,读出这个Binder对象,调用它的getBitmap函数拿到Bitmap。
注意下,putBinder 方式 只在Android 4.3 (api 18)及以上才有,所以我们做下判断。
发送端:
private void ipcBitmapBinder() {
        Intent intent = new Intent(this, SecondActivity.class);
        Bundle bundle = new Bundle();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            bundle.putBinder(“bitmap”, new ImageBinder(mBitmap));
        }
        intent.putExtras(bundle);
        startActivity(intent);
    }
接收端:
Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                ImageBinder imageBinder = (ImageBinder) bundle.getBinder(“bitmap”);
                Bitmap bitmap = imageBinder.getBitmap();
                mTv.setText(String.format((“bitmap大小为%dkB”), bitmap.getByteCount() / 1024));
                mIv.setImageBitmap(bitmap);
            }
        }
ImageBinder 是个继承自Binder的类,提供获取图片的方式:
class ImageBinder extends Binder {
    private Bitmap bitmap;
    public ImageBinder(Bitmap bitmap) {
        this.bitmap = bitmap;
    }
    Bitmap getBitmap() {
        return bitmap;
    }
}
2,107次阅读

Post navigation

前一篇:

CAN信号的c语言解析代码

后一篇:

用LVGL图形库绘制二维码

发表回复 取消回复

要发表评论,您必须先登录。

个人介绍

需要么,有事情这里找联系方式:关于天楚锐齿

=== 美女同欣赏,好酒共品尝 ===

微信扫描二维码赞赏该文章:

扫描二维码分享该文章:

分类

  • Linux&Android (81)
  • Uncategorized (1)
  • 下载 (28)
  • 云计算 (38)
  • 人工智能 (9)
  • 大数据 (35)
  • 嵌入式 (34)
  • 杂七杂八 (35)
  • 物联网 (65)
  • 网络 (25)
  • 通信 (22)

归档

近期文章

  • 飞书机器人发送卡片interactive消息
  • Springboot JPA实现对数据库表统一的增删改查
  • WEB的内容安全策略CSP(Content-Security-Policy)
  • CSS利用@media和viewport实现响应式布局自动适配手机电脑等
  • VUE前端增加国际化支持

近期评论

  • linux爱好者 发表在《Linux策略路由及iptables mangle、ip rule、ip route关系及一种Network is unreachable错误》
  • maxshu 发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition 发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition 发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • maxshu 发表在《Android9下用ethernet 的Tether模式来做路由器功能》

阅读量

  • 使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序 - 23,805次阅读
  • 卸载深信服Ingress、SecurityDesktop客户端 - 18,512次阅读
  • 车机技术之车规级Linux-Automotive Grade Linux(AGL) - 10,564次阅读
  • linux下的unbound DNS服务器设置详解 - 9,321次阅读
  • 在Android9下用ndk编译vSomeIP和CommonAPI以及使用例子 - 9,133次阅读
  • linux的tee命令导致ssh客户端下的shell卡住不动 - 8,638次阅读
  • Linux策略路由及iptables mangle、ip rule、ip route关系及一种Network is unreachable错误 - 8,125次阅读
  • 车机技术之360°全景影像(环视)系统 - 8,085次阅读
  • 车机技术之Android Automotive - 7,939次阅读
  • Windows下安装QEMU并在qemu上安装ubuntu和debian - 7,839次阅读

其他操作

  • 注册
  • 登录
  • 条目 feed
  • 评论 feed
  • WordPress.org

联系方式

地址
深圳市科技园

时间
周一至周五:  9:00~12:00,14:00~18:00
周六和周日:10:00~12:00

标签

android AT命令 CAN centos docker Hadoop hdfs ip java kickstart linux mapreduce mini6410 modem nova OAuth openstack os python socket ssh uboot 内核 协议 安装 嵌入式 性能 报表 授权 操作系统 数据 数据库 月报 模型 汽车 深信服 源代码 统计 编译 脚本 虚拟机 调制解调器 车机 金融 鉴权
© 2025 天楚锐齿