2012-01-17 37 views
7

Tôi đã chạy vào những gì tôi chỉ có thể phân loại là rò rỉ bộ nhớ cho các phần tử ScrollView khi sử dụng thành phần Thư viện.Thêm một ScrollView đơn giản vào Bộ sưu tập gây rò rỉ bộ nhớ

Một nền ngắn. Tôi đã có một ứng dụng hiện có là một ứng dụng trình chiếu hình ảnh. Nó sử dụng thành phần Thư viện, nhưng mỗi phần tử trong bộ điều hợp được hiển thị ở chế độ toàn màn hình. (nguồn đầy đủ có sẵn tại this link)

Bộ điều hợp Xem phần tử bao gồm một ImageView và hai TextView cho tiêu đề và mô tả. Khi ảnh có độ phân giải khá cao, ứng dụng sử dụng khá nhiều bộ nhớ nhưng Bộ sưu tập nói chung quản lý để tái chế chúng tốt.

Tuy nhiên, khi tôi hiện đang triển khai một ScrollView cho TextView mô tả, tôi gần như ngay lập tức gặp vấn đề về bộ nhớ. Đây là thay đổi duy nhất tôi đã thực hiện

<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> 

Tôi đã thực hiện một khối đống và có thể thấy rõ rằng đó là Scrollview vốn là gốc của các vấn đề về bộ nhớ.

Dưới đây là hai ảnh chụp màn hình từ phân tích kết xuất đống. Lưu ý rằng scrollview giữ một tham chiếu đến mParent trong đó bao gồm ảnh lớn tôi sử dụng Heap analysis - leak candidate Heap analysis - drilldown to a single ScrollView

PS cùng một vấn đề xảy ra nếu tôi sử dụng di chuyển của TextView (android: scrollbars = "thẳng đứng" và .setMovementMethod (mới ScrollingMovementMethod());

PSS thử tắt bộ nhớ cache vẽ dai dẳng, nhưng không dreaandroid khác nhau: persistentDrawingCache = "none"

Trả lời

3

Chỉ cần thêm này -> 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"> 

Có một số nguồn tại sao điều này là xuất hiện: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/view/View.java

vấn đề là:

setScrollContainer(boolean isScrollContainer) 

bởi mặc định:

boolean setScrollContainer = false; 

nhưng trong một số trường hợp như thế này

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

nó có thể là sự thật, và khi nó happends

/** * Thay đổi cho dù quan điểm này là một trong những bộ đồ chứa cuộn trong * của nó cửa sổ. Điều này sẽ được sử dụng để xác định xem cửa sổ có thể * thay đổi kích thước hoặc phải xoay khi vùng nhập mềm mở - scrollable * container cho phép cửa sổ sử dụng chế độ thay đổi kích cỡ kể từ vùng chứa * sẽ thu nhỏ một cách thích hợp. */

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) - tất cả các quan điểm đưa vào ArrayList điều này dẫn đến rò rỉ bộ nhớ đôi khi

+0

Tuyệt vời, điều này dường như đã giải quyết được sự rò rỉ bộ nhớ. Tuy nhiên, tôi không thể tự động cuộn TextView. Đây là mã tôi đang cố gắng sử dụng slideshowDescription.setText (slideshowPhoto.getDescription()); Scroller scroller = new Scroller (ngữ cảnh); slideshowDescription.setScroller (cuộn); cuộn.computeScrollOffset(); int descriptionBottom = slideshowDescription.getBottom(); scroller.startScroll (slideshowDescription.getScrollX(), slideshowDescription.getScrollY(), 0, descriptionBottom, 400); – dparnas

+0

Dường như tôi đã chạy vào vấn đề khét tiếng với chiều cao và các thuộc tính khác không được khởi tạo và do đó có giá trị 0. Nên có thể mã xung quanh đó. Cảm ơn – dparnas

+0

Đã không nhận được cách tiếp cận này để làm việc, nhưng đã tìm thấy một workaround mà tôi sẽ đăng – dparnas

2

có tôi nhận thấy vấn đề này, xin lỗi vì bình luận trước đây của tôi, tôi đã cố gắng để làm trống Drawables bởi đặt trước Drawable.setCallBack(null); nhưng không làm việc, btw tôi có gần như cùng một dự án, tôi sử dụng ViewFlipper thay vì Gallery, vì vậy tôi có thể kiểm soát mọi thứ, và tôi chỉ sử dụng 2 Views trong đó, và chuyển đổi giữa chúng, và không bị rò rỉ bộ nhớ, và tại sao không phải bạn thay đổi kích thước hình ảnh trước khi hiển thị nó, do đó, nó sẽ làm giảm việc sử dụng bộ nhớ (tìm kiếm SO để thay đổi kích thước hình ảnh trước khi đọc nó)

+0

Nếu tôi đã bắt đầu từ đầu, tôi muốn sử dụng ViewFlipper là tốt. Nhưng ngay bây giờ tôi khá cam kết sử dụng Gallery và rò rỉ bộ nhớ ScrollView này là gây phiền nhiễu cho tôi khá một chút – dparnas

4

Bạn đã thử xóa chế độ xem bất cứ khi nào chế độ xem vùng chứa cuộn ra khỏi màn hình? Tôi không chắc liệu điều đó có phù hợp với bạn hay không nhưng nó đáng giá? Ngoài ra, hãy thử gọi setScrollContainer (false) trên màn hình cuộn khi nó rời khỏi màn hình. Điều đó dường như loại bỏ khung nhìn từ tập hợp mScrollContainers.

Ngoài ra, this question, được trả lời bởi Dianne Hackborn (kỹ sư android), tuyên bố rõ ràng là không sử dụng chế độ xem cuộn bên trong Thư viện. Có lẽ vấn đề này là lý do tại sao?

+0

Cảm ơn cho đầu vào. Hãy suy nghĩ đây là gần như là một câu trả lời tôi sẽ nhận được. Tuy nhiên, tôi nghĩ rằng nó sẽ không giải quyết nó hoàn toàn. Tôi có lẽ có thể loại bỏ scrollview khi tôi đang trong onfling hoặc khi tôi từ các ứng dụng kích hoạt một quá trình chuyển đổi. Nhưng khi adapter được sửa đổi với notifyDataSetChanged sẽ khó khăn hơn – dparnas

0

Thử di chuyển "android: layout_below =" @ id/slideshow_title "trong TextView sang ScrollView.

0

Đã kết thúc với việc thực hiện một cách giải quyết có sử dụng một TextSwitcher cũng được thay đổi để chuỗi con còn lại mỗi x giây.

Dưới đây là định nghĩa liên quan xml từ cách bố trí

 <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> 

Ở đây tôi thêm hình ảnh động chuyển đổi sang TextSwitcher (trong phương pháp getView của bộ chuyển đổi)

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

Sau đây là cách tôi trao đổi với một phần của mô tả

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

    } 

Và cuối cùng, đây là nơi tôi thiết lập Bộ hẹn giờ gây nó để cập nhật mỗi 3,5 giây

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

Cuối cùng tôi có thể đưa vấn đề này để nghỉ ngơi :)