Android ImageView:如果ImageView不可见(在ScrollView中),则自动循环使用位图

Android ImageView:如果ImageView不可见(在ScrollView中),则自动循环使用位图,android,memory,bitmap,imageview,scrollview,Android,Memory,Bitmap,Imageview,Scrollview,所以,我已经研究ImageView源代码一段时间了,但我还没有找到一个钩子来实现这一点 问题是:一个ScrollView中有30个400x800图像(图像的数量是可变的)。由于它们完全适合屏幕,因此每个内存将占用1.3MB 我想要的是:能够加载/卸载当前在ScrollView中可见的ImageView位图。如果用户滚动并且位图不再可见(在距离阈值内),则应循环使用位图,以便同一滚动视图中的其他位图可以使用内存。我正在做下采样和所有这些,所以不用担心。如果您仅通过扩展ImageView(如果可能的

所以,我已经研究ImageView源代码一段时间了,但我还没有找到一个钩子来实现这一点

问题是:一个ScrollView中有30个400x800图像(图像的数量是可变的)。由于它们完全适合屏幕,因此每个内存将占用1.3MB

我想要的是:能够加载/卸载当前在ScrollView中可见的ImageView位图。如果用户滚动并且位图不再可见(在距离阈值内),则应循环使用位图,以便同一滚动视图中的其他位图可以使用内存。我正在做下采样和所有这些,所以不用担心。如果您仅通过扩展ImageView(如果可能的话,我不想弄乱ScrollView)来实现这一点,将获得额外的积分

小结:我只能在ImageView可见后(使用巧妙的技巧)加载图像,但我不知道何时卸载它们


注意:由于其他可用性原因,我无法使用ListView执行此操作。

您真正想要的是为此使用ArrayAdapter。如果像您的笔记所建议的那样,这是不可能的(尽管我不明白为什么),请查看array adapter的源代码,并根据您自己的需要重写一个

看一看android文档,其中也有一个名为bitmap fun的代码示例

如果使用ListView或GridView,则ImageView对象将被回收,实际位图将被释放以供GC清理


您还需要将原始图像调整为屏幕大小,并将其缓存在磁盘和/或RAM上。这将为您节省大量空间,实际大小应降至几百KB。您还可以尝试以显示器一半的分辨率显示图像。当使用更少的RAM时,结果应该仍然很好。

当您想要回收位图时,调用此方法

public static void recycleImagesFromView(View view) {
            if(view instanceof ImageView)
            {
                Drawable drawable = ((ImageView)view).getDrawable();
                if(drawable instanceof BitmapDrawable)
                {
                    BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
                    bitmapDrawable.getBitmap().recycle();
                }
            }

            if (view instanceof ViewGroup) {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                    recycleImagesFromView(((ViewGroup) view).getChildAt(i));
                }
            }
        }
publicstaticvoidrecycleImagesfromview(视图){
if(图像视图的视图实例)
{
Drawable Drawable=((ImageView)视图).getDrawable();
if(BitmapDrawable的可绘制实例)
{
BitmapDrawable BitmapDrawable=(BitmapDrawable)drawable;
bitmapDrawable.getBitmap().recycle();
}
}
if(视图组的视图实例){
对于(int i=0;i<((视图组)视图)。getChildCount();i++){
recycleImagesFromView(((视图组)视图).getChildAt(i));
}
}
}

我已经使用阵列适配器生成了包含这些ImageView的组件。ArrayAdapter本身并不聪明。当视图移出视图(或多或少)时,阵列适配器会从所有视图中释放其引用。这将强制您的图像自动回收。您不需要在图像上显式调用recycle。但是,您需要确保没有对位图的强引用,这样才能发布它们。我所做的只是将图像存储在文件系统上,然后在getView上,将位图绑定到文件系统中的视图。同样,这不是适配器所做的,而是持有适配器的任何操作,在本例中,可能是ListView。适配器本身除了返回一个新的视图或重用回收的视图(如果提供的话)之外什么都不做。我明白你的意思。因为你不想使用ListView,你也不想使用适配器。是的,对于ListView,这将是“默认”行为。这是专门为ScrollView设计的,我最后想出来了,但并不漂亮。@dmon您能分享解决方案的任何部分吗?您是否100%确定ListView会在视图失去焦点时自动处理视图?这适用于所有Android版本,还是2.2+版本?我编写的最低API版本是7级。我可以在这里发布更多信息。现在有点忙。但也许在本周末,我们需要一个大致的答案。但是你确定这是有效的并且不会造成相当大的延迟吗?我添加了一个缺少的null检查,因为getBitmap()可能返回null;请参阅BitmapDrawable.java:“返回此可绘制文件用于渲染的位图。可能为空。”