bingoogolapple / BGAPhotoPicker-Android

Android 图片选择、预览、九宫格图片控件、拖拽排序九宫格图片控件
2.24k stars 413 forks source link

手机图片过多时,在选择图片的时候点击预览图片会报错闪退! #139

Closed Leu-Z closed 4 years ago

Leu-Z commented 6 years ago

测试手机上有7500多张图片,在选择图片的时候,只要点击一张图片进行预览,就会报错。

JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 1043708) Caused by: android.os.TransactionTooLargeException: data parcel size 1043708 bytes

libern commented 6 years ago

我有6057,也遇到相同问题。直接显示的感觉像闪退一样的。

但是我如果切换文件夹到169张的的,就没有问题,能预览了。

liuhuan8986 commented 6 years ago

我也遇到这个问题了:android.os.TransactionTooLargeException: data parcel size 1109536 bytes,请问修复了没

Leu-Z commented 6 years ago

@liuhuan8986 没有修复

liuhuan8986 commented 6 years ago

那只能换一种方式传递数据了

CaiJinFu commented 6 years ago

我的项目也是遇到这个问题,有解决的方案吗?

ghost commented 6 years ago

我这边图片没你们那么多,不过滑动的时候立即返回也会蹦掉,日志如下: java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity at com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed(RequestManagerRetriever.java:323) at com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:157) at com.bumptech.glide.Glide.with(Glide.java:719) at cn.bingoogolapple.photopicker.imageloader.BGAGlideImageLoader.resume(BGAGlideImageLoader.java:91) at cn.bingoogolapple.photopicker.imageloader.BGAImage.resume(BGAImage.java:110) at cn.bingoogolapple.photopicker.imageloader.BGARVOnScrollListener.onScrollStateChanged(BGARVOnScrollListener.java:36) at android.support.v7.widget.RecyclerView.dispatchOnScrollStateChanged(RecyclerView.java:4998) at android.support.v7.widget.RecyclerView.setScrollState(RecyclerView.java:1545) at android.support.v7.widget.RecyclerView.stopScroll(RecyclerView.java:2330) at android.support.v7.widget.RecyclerView.onDetachedFromWindow(RecyclerView.java:2827) at android.view.View.dispatchDetachedFromWindow(View.java:14752) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3224) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3216) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3216) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3216) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3216) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3216) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3216) at android.view.ViewRootImpl.dispatchDetachedFromWindow(ViewRootImpl.java:3502) at android.view.ViewRootImpl.doDie(ViewRootImpl.java:6182) at android.view.ViewRootImpl.die(ViewRootImpl.java:6154) at android.view.WindowManagerGlobal.removeViewLocked(WindowManagerGlobal.java:419) at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:374) at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:116) at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4101) at android.app.ActivityThread.-wrap5(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1542) at android.os.Handler.dispatchMessage(Handler.java:111) at android.os.Looper.loop(Looper.java:207) at android.app.ActivityThread.main(ActivityThread.java:5728) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679) 然后在BGAImage的108L resume()中处理了isFinishing判断,以及BGAGlideImageLoader的resume()都加了判断就没崩了。

Leu-Z commented 6 years ago

@likealeodog 你碰到的应该跟我不是同一个问题

Leu-Z commented 6 years ago

有空查了一下这个问题出现的原因,最终定位到错误原因是从选择图片Activity传递到预览图片Activity的图片地址List太大了,超过了Intent传递最大数据量1MB,导致异常。 通过查阅其他同类图片选择库的源码(比如bilibili和知乎开源的),发现都是在预览图片Activity重新获取一遍所有图片,所以不存在传递这个步骤。

下面是自己总结的TransactionTooLargeException异常解析以及Activity之间传递大数据的解决方案。不知道怎么联系作者,希望可以尽早更新。

问题原因

当传递数据量过大,比如list的size过大,会导致Activity无法启动。现象即启动失败,activityB的oncreate()都不会执行。 分析: 官方文档提到TransactionTooLargeException异常,“The Binder transaction failed because it was too large.”即传输数据过大异常。 并且提到这样一句话:“Parcel objects stored in the Binder transaction buffe”,这表明实际上底层parcel对象在不同activity直接传递过程中保存在一个叫做“ Binder transaction buffe”的地方,既然是缓冲区,肯定有大小限制。 官方文档还提到 “The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.” 即缓冲区最大1MB,并且这是该进程中所有正在进行中的传输对象所公用的。至于都有哪些传输对象、具体怎么分配,这个还不太清楚。可以肯定的是Activity之间使用Parcel传输数据是有大小限制的。那么在传输大小可能很大的情况下就要做点处理了。

解决方法

一、EventBus

EventBus.getDefault().postSticky(imageList);

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void getImageData(ArrayList<String> imageList) {
     mImageList = imageList;
}

二、静态static

将传递的信息封装在一个静态的类中,或则封装在跳转对象的一个静态属性中,效率高,但是耦合性也高! (这种方法在stackoverflow网站看到的,有兴趣可以点击查看详情)

 Intent intent = new Intent(this,SecondActivity.class);
 DataSave.setValue(value);//将value设置到静态类DataSave中
 //SecondActivity.value = value;//或则将value设置到SecondActivity的静态属性中
 startActivity(intent);

三、持久化

将传递的信息做本地存储,如SP存储、数据库等,然后在跳转对象中取出来,不会提高程序的耦合性,但是效率较低。

相对于数据库而言,个人比较喜欢sp存储,因为比较简单。
1、存储基本类型这个不多说
2、存储实体类,首先可以使用Gson将实体转为json串(可以使用new Gson().toJson()方法),然后进行存储,最后在跳转对象中取出再利用Gson转为实体即可(可以使用new Gson().fromJson()方法)。

四、单例

省略。。。

chenyabingsuny commented 5 years ago

反射打补丁吧,改了数据传递方式