添加一个简单的ScrollView到图库导致内存泄漏

我遇到了我只能用ScrollView元素在使用Gallery组件时分类为内存泄漏的情况。

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

适配器视图元素由一个ImageView和两个用于标题和描述的TextView组成。 由于照片的分辨率相当高,该应用程序使用了相当多的内存,但是图库一般都能够很好地回收它们。

但是,当我现在正在实现一个描述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> 

我做了一个堆转储,可以清楚地看到,这是内存问题的根源滚动查看。

以下是堆转储分析的两个屏幕截图。 请注意,ScrollView保留了mParent的参考,其中包括我使用的大照片 堆分析 - 泄漏候选人堆分析 - 深入到单个ScrollView

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

PSS尝试closures持久性绘图caching,但没有不同的dreaandroid:persistentDrawingCache =“none”

Related of "添加一个简单的ScrollView到图库导致内存泄漏"

只要添加这个 – > 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"> 

有一些来源,为什么出现: http : //grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/view/View.java

问题是:

 setScrollContainer(boolean isScrollContainer) 

默认:

 boolean setScrollContainer = false; 

但在某些情况下是这样的

 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { setScrollContainer(true); } 

它可以是真实的,当它发生时

/ ** *改变这个视图是否是其窗口中的一组可滚动容器。 这将用于确定当软input区域打开时,窗口是否可以*resize或者必须平移 – 可滚动容器允许窗口使用resize模式,因为容器*将适当缩小。 * /

 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); } } 

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

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

此外,Dianne Hackborn(android工程师)回答的这个问题明确指出,不要在图库中使用可滚动的视图。 也许这个问题是为什么呢?

是的,我注意到这个问题,对于我之前的评论感到抱歉,我试图通过设置前面的Drawable.setCallBack(null);来清空Drawable Drawable.setCallBack(null); 但没有工作,顺便说一句,我有几乎相同的项目,我使用ViewFlipper而不是画廊,所以我可以控制每一件事,我只是使用2视图,并切换它们之间,没有内存泄漏,为什么不resize显示它之前的图像,所以它会减less内存使用量(searchSOresize的图像之前阅读)

尝试在TextView中将“android:layout_below =”@ id / slideshow_title“移动到ScrollView。

最后实现一个解决scheme,该解决scheme使用每隔x秒自动更改为剩余子string的TextSwitcher。

以下是布局中的相关xml定义

  <TextSwitcher android:id="@+id/slideshow_description" android:textSize="@dimen/description_font_size" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/slideshow_description_anim1" android:textSize="@dimen/description_font_size" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="2" android:textColor="@color/white" android:singleLine="false"/> <TextView android:id="@+id/slideshow_description_anim2" android:textSize="@dimen/description_font_size" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="2" android:textColor="@color/white" android:singleLine="false"/> </TextSwitcher> 

在这里,我将转换animation添加到TextSwitcher(在适配器的getView方法中)

 final TextSwitcher slideshowDescription = (TextSwitcher)slideshowView.findViewById(R.id.slideshow_description); Animation outAnim = AnimationUtils.loadAnimation(context, R.anim.slide_out_down); Animation inAnim = AnimationUtils.loadAnimation(context, R.anim.slide_in_up); slideshowDescription.setInAnimation(inAnim); slideshowDescription.setOutAnimation(outAnim); 

这是我如何交换的描述的一部分

  private void updateScrollingDescription(SlideshowPhoto currentSlideshowPhoto, TextSwitcher switcherDescription){ String description = currentSlideshowPhoto.getDescription(); TextView descriptionView = ((TextView)switcherDescription.getCurrentView()); //note currentDescription may contain more text that is shown (but is always a substring String currentDescription = descriptionView.getText().toString(); if(currentDescription == null || description==null){ return; } int indexEndCurrentDescription= descriptionView.getLayout().getLineEnd(1); //if we are not displaying all characters, let swap to the not displayed substring if(indexEndCurrentDescription>0 && indexEndCurrentDescription<currentDescription.length()){ String newDescription = currentDescription.substring(indexEndCurrentDescription); switcherDescription.setText(newDescription); }else if(indexEndCurrentDescription>=currentDescription.length() && indexEndCurrentDescription<description.length()){ //if we are displaying the last of the text, but the text has multiple sections. Display the first one again switcherDescription.setText(description); }else { //do nothing (ie. leave the text) } } 

最后,这里是我设置定时器,使其每3.5秒更新一次

  public void setUpScrollingOfDescription(){ final CustomGallery gallery = (CustomGallery) findViewById(R.id.gallery); //use the same timer. Cancel if running if(timerDescriptionScrolling!=null){ timerDescriptionScrolling.cancel(); } timerDescriptionScrolling = new Timer("TextScrolling"); final Activity activity = this; long msBetweenSwaps=3500; //schedule this to timerDescriptionScrolling.scheduleAtFixedRate( new TimerTask() { int i=0; public void run() { activity.runOnUiThread(new Runnable() { public void run() { SlideshowPhoto currentSlideshowPhoto = (SlideshowPhoto)imageAdapter.getItem(gallery.getSelectedItemPosition()); View currentRootView = gallery.getSelectedView(); TextSwitcher switcherDescription = (TextSwitcher)currentRootView.findViewById(R.id.slideshow_description); updateScrollingDescription(currentSlideshowPhoto,switcherDescription); //this is the max times we will swap (to make sure we don't create an infinite timer by mistake if(i>30){ timerDescriptionScrolling.cancel(); } i++; } }); } }, msBetweenSwaps, msBetweenSwaps); } 

最后我可以把这个问题rest一下:)