Android Intent 传输大图片

   日期:2020-06-04     浏览:106    评论:0    
核心提示:Android中的Intent作为四大组件间通讯的桥梁,支持传输基本数据类型、序列化对象等等但是要传大图片呢?能不能传呢?下面开始做个试验,先准备一张近500k大小的图片,存放在mipmap下直接通过Intent的putExtra方法传输,并且打印bitmap大小。Intentintent=newIntent(this,Main2Activity.class);bitmap=BitmapFactory.decodeResource(getResources(),R.mipmap.

Android中的Intent作为四大组件间通讯的桥梁,支持传输基本数据类型、序列化对象等等

但是要传大图片呢?能不能传呢?下面开始做个试验,先准备一张近500k大小的图片,存放在mipmap下


直接通过Intent的putExtra方法传输,并且打印bitmap大小。

Intent intent = new Intent(this, Main2Activity.class);
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.abc);
Log.i("MainActivity", "bitmap大小: " + bitmap.getByteCount() / 1024 + " kb");
intent.putExtra("bitmap", bitmap);
startActivity(intent);

运行结果
控制台打印了bitmap的大小

bitmap大小: 116109 kb

但是应用崩溃了,抛了TransactionTooLargeException异常,意思是交易数据过大?

原因是调用Binder IPC时,系统会临时分配一块缓冲内存,并且大小只有1M,所以使用Intent传递数据的时候(底层实际也是使用Binder IPC),数据超过限制时(1M 减去 其他事务使用的内存)就会抛出该异常。详见 Android 面试官的《跨进程传递大图,你能想到哪些方案呢?》

解决方案

1、传递路径方式

可以将图片保存在文件中,再将图片路径传给目标组件,目标组件用路径获取该图片。该方案可行,缺点是性能不高,所以不推荐。

2、Socket 方式

数据会拷贝两次,同样也有性能缺陷,所以也不推荐(没用过)

3、数据分组方式

将图片转成字节数组,分组通过Intent传递,目标组件获取所有的数据后再重新组合,太麻烦了,估计也没人这样做。

4、Binder IPC 方式

前面也验证过直接用Intent传大图是不可行的,但是细心的我们发现,Bundle有个putBinder方法

public void putBinder(@Nullable String key, @Nullable IBinder value) {
    unparcel();
    mMap.put(key, value);
}

可以看到,第二个参数接收的是一个IBinder对象,我们可以用这个IBinder接收Bitmap,然后通过putBinder方法传给目标组件。下面看看用法

Bundle#putBinder使用

来个简单的例子,新建一BitmapBinder继承Binder

public class BitmapBinder extends Binder {
    private Bitmap bitmap;

    BitmapBinder(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

    Bitmap getBitmap() {
        return bitmap;
    }
}

通过putBinder传递Bitmap,并打印bitmap大小

Intent intent = new Intent(this, Main2Activity.class);
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.abc);
Bundle bundle = new Bundle();
Log.i("MainActivity", "bitmap大小: " + bitmap.getByteCount() / 1024 + " kb");
bundle.putBinder("bitmap", new BitmapBinder(bitmap));
intent.putExtras(bundle);

在接收组件接收,并打印bitmap大小

Bundle bundle = getIntent().getExtras();
BitmapBinder bitmapBinder = (BitmapBinder) bundle.getBinder("bitmap");
bitmap = bitmapBinder.getBitmap();
Log.i("MainActivity", "Mani2Activity bitmap 大小" + bitmap.getByteCount() / 1024 + " kb");

最终的结果是正常跳转,并且日志输出如下。可见使用该方式可以解决Activity之间传递大图的问题。

bitmap大小: 116109 kb
Mani2Activity bitmap 大小116109 kb

结论: Intent直接传递是将数据拷贝到Binder的缓冲内存中(大小限制了1M);putBinder则是利用共享内存,所以能满足大图传输,原理详见 Android 面试官的《跨进程传递大图,你能想到哪些方案呢?》

拓展

如果传递的是超长的String数组呢?这里猜测也会抛数据过大的异常。

这里将一个txt文件存放在assets目录,然后将内容读取,打印内容长度内容大小478 kb,然后直接使用Intent传递,可以看到同样抛了一样的异常,可见传递超长的基本数据类型也是不可行的

使用putBinder方法,代码类似传递大图,结果是可以传递

InputStream inputStream = getAssets().open("txt.txt");
int lenght = inputStream.available();
byte[] bytes = new byte[lenght];
int read = inputStream.read(bytes);
String txtContent = new String(bytes, StandardCharsets.UTF_8);
Log.i("MainActivity", "txt 内容大小" + txtContent.length() / 1024 + " kb");
bundle.putBinder("txt",new BitmapBinder(txtContent));

日志输出

txt 内容大小478 kb
Mani2Activity txt 内容大小478 kb

其实结果也没什么可说的,原理和之前的大图类似。所以,如果平时开发过程中遇到要传递大图片或超长字符串等,可以考虑使用这种方法。

欢迎关注我的个人微信公众号,【优了个秀】和你每天进步一点点

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服