完美解决Activity之间传输Bitmap的三种方式

快速COPY,请滑到最后

因为Intent只能传输数据容量很小的基本数据,当位图很大的时候,很有可能会出现传输错误

为什么不能传输很大的Bitmap呢?

Intent 传递大数据,会出现 TransactionTooLargeException 的场景,在 TransactionTooLargeException(https://developer.android.com/reference/android/os/TransactionTooLargeException.html) 的文档中,其实已经将触发原因详细说明了。

问题思路:

Intent 传输数据的机制中,用到了 Binder。Intent 中的数据,会作为 Parcel 被存储在 Binder 的事务缓冲区(Binder transaction buffer)中的对象进行传输。而这个 Binder 事务缓冲区具有一个有限的固定大小,当前为 1MB。可别以为传递 1MB 以下的数据就安全了,这里的 1MB 空间并不是当前操作独享的,而是由当前进程所共享。也就是说 Intent 在 Activity 间传输数据,本身也不适合传递太大的数据。

细节说明1:

Intent 使用 Bundle 存储数据,到底是值传递(深拷贝)还是引用传递?

1、 Intent 传输的数据,都存放在一个 Bundle 类型的对象 mExtras 中,Bundle 要求所有存储的数据,都是可被序列化的。

2、在 Android 中,序列化数据需要实现 Serializable 或者 Parcelable。对于基础数据类型的包装类,本身就是实现了 Serializable,而我们自定义的对象,按需实现这两个序列化接口的其中一个即可。

细节说明2: 是不是只要通过 Bundle 传递数据,就会面临序列化的问题?

并不是,Activity 之间传递数据,首先要考虑跨进程的问题,而 Android 中又是通过 Binder 机制来解决跨进程通信的问题。涉及到跨进程,对于复杂数据就要涉及到序列化和反序列化的过程,这就注定是一次值传递(深拷贝)的过程。

这个问题用反证法也可以解释,如果是引用传递,那传递过去的只是对象的引用,指向了对象的存储地址,就只相当于一个 Int
的大小,也就根本不会出现 TransactionTooLargeException 异常。

细节说明3:传输数据序列化和 Bundle 没有关系,只与 Binder 的跨进程通信有关。

在 Android 中,使用 Bundle 传输数据,并非 Intent 独有的。例如使用弹窗时,DialogFragment 中也可以通过 setArguments(Bundle) 传递一个 Bundle 对象给对话框。

Fragment 本身是不涉及跨进程的,这里虽然使用了 Bundle 传输数据,但是并没有通过
Binder,也就是不存在序列化和反序列化。和 Fragment 数据传递相关的 Bundle,其实传递的是原对象的引用。

如何解决:

原因既然在于 Binder 传输限制了数据的大小,那我们不走 Binder 通信就好了。

可以从数据源上来考虑:

例如 Bitmap,本身就已经实现了 Parcelable 是可以支持序列化的。用 Intent 传输,稍微大一点的图一定会出现
TransactionTooLargeException。当然真是业务场景,肯定不存在传递 Bitmap 的情况。

那就先看看这个图片的数据源。Drawable?本地文件?线上图片?无论数据源在哪里,我们只需要传递一个
drawable_id、路径、URL,就可以还原这张图片,无需将这个 Bitmap
对象传递过去。大数据总有数据源,从数据源还原数据,对我们而言只是调用一个方法而已。
源自《Android 开发者手册》

第一种:使用Intent,通过parcelable方式传递

//Activity One 【第一个活动ActivityA (传递)】
Intent intent = new Intent(this, Two.class);
intent.putExtra("key", bitmap);

//Activity Two 【第二个活动ActivityB  (接收)】
//接收类型为 Bitmap ,通过getParcelableExtra接收key
Intent intent = new Intent();
Bitmap bitmap = (Bitmap) intent.getParcelableExtra("key");

注意:在第二个活动中,Bitmap一定要强转(Bitmap)不然拿不到

第二种:使用Intent,通过字节数组传递

//Activity One 【第一个活动ActivityA (传递)】
Intent intent = new  Intent(this,Two.class);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bs);
byte[] bitmapByte = bs.toByteArray();
intent.putExtra("bp", bitmapByte);
this.startActivity(intent);

//Activity Two 【第二个活动ActivityB  (接收)】
byte[] byteTemp = intent.getByteArrayExtra("bitmap");
bitmap = BitmapFactory.decodeByteArray(byteTemp, 0, byteTemp.length);

第三种:以流的形式写入到文件到,通过Intent传文件路径到另一个Activity

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Environment;

public class BitmapUtil
{
        /**
         * 保存Bitmap为文件;可能报空指针是因为没有配置权限
         *
         * @param bmp
         * @param filename
         * @return
         */
public static void saveBitmap2file(Bitmap bmp, String filename){
     CompressFormat format = Bitmap.CompressFormat.JPEG;
     int quality = 100;
     OutputStream stream = null;
     try{
     stream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()
                                        + "/"
                                        + filename
                                        + ".jpg");
     } catch (FileNotFoundException e){
       e.printStackTrace();
     }
	   bmp.compress(format, quality, stream);
     try{
        stream.flush();
        stream.close();
        } catch (IOException e){
         e.printStackTrace();
        }
    }

        /**
         * 读取文件为Bitmap
         *
         * @param filename
         * @return
         * @throws FileNotFoundException
         */
public static Bitmap getBitmapFromFile(String filename){
                try{
                return BitmapFactory.decodeStream(newFileInputStream(Environment.getExternalStorageDirectory().getPath()
                                        + "/"
                                        + filename
                                        + ".jpg"));
                } catch (FileNotFoundException e){
                        e.printStackTrace();
                }
                return null;
        }

}
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

其子昱舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值