将简单的ScrollView添加到Gallery会导致内存泄漏

dpa*_*nas 8 memory android scrollview

在使用Gallery组件时,我遇到了我只能归类为ScrollView元素的内存泄漏的问题.

简短的背景.我有一个现有的应用程序是一个照片幻灯片应用程序.它使用Gallery组件,但适配器中的每个元素都以全屏显示.(此链接提供完整的来源)

适配器View元素包含一个ImageView,以及两个用于标题和描述的TextView.由于照片分辨率非常高,因此该应用程序使用了相当多的内存,但Gallery通常会设法好好回收它们.

但是,当我现在为描述TextView实现ScrollView时,我几乎立即遇到了内存问题.这是我做的唯一改变

<ScrollView
android:id="@+id/description_scroller"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:fillViewport="true">
  <TextView
    android:id="@+id/slideshow_description"
    android:textSize="@dimen/description_font_size"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@color/white"
    android:layout_below="@id/slideshow_title"
    android:singleLine="false"
    android:maxLines="4"/>  
</ScrollView> 
Run Code Online (Sandbox Code Playgroud)

我做了堆转储,可以清楚地看到Scrollview是内存问题的根源.

以下是堆转储分析的两个屏幕截图.请注意,ScrollView保留对mParent的引用,其中包含我使用的大型照片 堆分析 - 泄漏候选人 堆分析 - 深入查看单个ScrollView

如果我使用TextView的滚动(android:scrollbars ="vertical"和.setMovementMethod(new ScrollingMovementMethod()),PS会出现同样的问题;

PSS尝试关闭持久绘图缓存,但没有不同的dreaandroid:persistentDrawingCache ="none"

Jus*_*ler 5

您是否尝试过在容器视图从屏幕滚动时删除滚动视图?我不确定这是否适合你,但值得一试吗?或者,尝试在滚动视图离开屏幕时调用 setScrollContainer(false) 。这似乎从 mScrollContainers 集中删除了视图。

此外,这个问题由 Dianne Hackborn(android 工程师)回答,明确声明不要在 Gallery 内使用可滚动视图。也许这个问题是为什么?


Nik*_*huk 3

只需添加此 -> android:isScrollContainer="false"

<ScrollView
    android:id="@+id/description_scroller"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:scrollbars="vertical"
    android:fillViewport="true"
    android:isScrollContainer="false">
Run Code Online (Sandbox Code Playgroud)

有一些来源出现这种情况: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/view/View.java

问题是:

setScrollContainer(boolean isScrollContainer)
Run Code Online (Sandbox Code Playgroud)

默认情况下:

boolean setScrollContainer = false;  
Run Code Online (Sandbox Code Playgroud)

但在某些情况下像这样

if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) {
    setScrollContainer(true);
}
Run Code Online (Sandbox Code Playgroud)

这可能是真的,当它发生时

/** * 更改此视图是否是其窗口中的一组可滚动容器之一。这将用于确定当软输入区域打开时窗口是否可以调整大小或必须平移 - 可滚动容器允许窗口使用调整大小模式,因为容器将适当缩小。*/

public void setScrollContainer(boolean isScrollContainer) {
    if (isScrollContainer) {
        if (mAttachInfo != null && (mPrivateFlags&SCROLL_CONTAINER_ADDED) == 0) {
            mAttachInfo.mScrollContainers.add(this);
            mPrivateFlags |= SCROLL_CONTAINER_ADDED;
        }
        mPrivateFlags |= SCROLL_CONTAINER;
    } else {
        if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) {
            mAttachInfo.mScrollContainers.remove(this);
        }
        mPrivateFlags &= ~(SCROLL_CONTAINER|SCROLL_CONTAINER_ADDED);
    }
}
Run Code Online (Sandbox Code Playgroud)

mAttachInfo.mScrollContainers.add(this) - 所有视图放入 ArrayList 这有时会导致内存泄漏