2013-08-06 26 views
3

使用ArrayAdapter我使用ArrayAdapter實現了getView()方法以這種方式創建一個ListView的OutOfMemoryError ListView中

public View getView(int position, View convertView, ViewGroup parent) { 
    View rowView = convertView; 
    if(rowView ==null){ 
    LayoutInflater inflater = (LayoutInflater) context 
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);   
    rowView = inflater.inflate(R.layout.rowlayout_member, parent, false); 
      } 
    TextView textView = (TextView) rowView.findViewById(R.id.label); 
    TextView textView1 = (TextView) rowView.findViewById(R.id.label1); 
    ImageView imageView = (ImageView) rowView.findViewById(R.id.icon); 
    textView.setText(values[position]); 
    textView1.setText(surname[position]); 

    String s = values[position]; 
    if(foto[position] != null){ 
    Drawable c = Drawable.createFromPath(basePath+foto[position]); // line 56 
    if(c!=null) 
     imageView.setImageDrawable(c); 
    else 
     imageView.setImageResource(R.drawable.default); 
    }else{ 
     imageView.setImageResource(R.drawable.default);     
    } 
    return rowView; 
} 

一切似乎做工精細,但當我進來和走出去的名單很多倍(改變活性)有時我得到如下錯誤:

08-06 15:06:14.110: E/dalvikvm-heap(3527): Out of memory on a 2380816-byte allocation. 
08-06 15:06:14.110: W/dalvikvm(3527): threadid=1: thread exiting with uncaught exception (group=0x40a3d1f8) 
08-06 15:06:14.120: E/AndroidRuntime(3527): FATAL EXCEPTION: main 
08-06 15:06:14.120: E/AndroidRuntime(3527): java.lang.OutOfMemoryError 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:299) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:324) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.graphics.drawable.Drawable.createFromPath(Drawable.java:880) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at host.framework.component.MySimpleArrayAdapter.getView(MySimpleArrayAdapter.java:56) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.widget.AbsListView.obtainView(AbsListView.java:2012) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.widget.ListView.makeAndAddView(ListView.java:1772) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.widget.ListView.fillUp(ListView.java:705) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.widget.ListView.fillGap(ListView.java:645) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4546) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:3813) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.os.Handler.handleCallback(Handler.java:605) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.os.Handler.dispatchMessage(Handler.java:92) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.os.Looper.loop(Looper.java:137) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at android.app.ActivityThread.main(ActivityThread.java:4424) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at java.lang.reflect.Method.invokeNative(Native Method) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at java.lang.reflect.Method.invoke(Method.java:511) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
08-06 15:06:14.120: E/AndroidRuntime(3527):  at dalvik.system.NativeStart.main(Native Method) 
08-06 15:06:14.120: W/ActivityManager(149): Force finishing activity host.activity/.ACT_CircoliDiSupporto 
08-06 15:06:14.640: W/ActivityManager(149): Activity pause timeout for ActivityRecord{413de508 host.activity/.ACT_CircoliDiSupporto} 
08-06 15:06:24.140: W/ActivityManager(149): Launch timeout has expired, giving up wake lock! 
08-06 15:06:24.650: W/ActivityManager(149): Activity idle timeout for ActivityRecord{41389d58 host.activity/.HostActivity} 

的線56(在代碼中突出顯示的)似乎產生錯誤

Drawable c = Drawable.createFromPath(basePath+foto[position]); 
+1

你正確釋放的對象?不要在getView()內部創建drawables ...至少只能創建一次,之後再使用該對象。 – 66CLSjY

+0

我怎樣才能確定我的對象被正確釋放?呃,也許你是對的:每次getView被稱爲一個新的Drawable被創建。 – GVillani82

回答

3

有許多與目前執行的問題:

  1. 訪問的代碼,並建立主/ UI線程(Drawable c = Drawable.createFromPath(basePath+foto[position]); // line 56)上的位圖,這將讓你列表滾動相當波濤洶涌
  2. 一每次請求視圖時都會創建新的可繪製對象,在2.x Android系統上,垃圾收集器(GC)收集未引用的位圖需要一段時間,從而加劇了內存問題
  3. 您從存儲沒有縮放到適當的大小,這可能會或可能不會成爲一個問題,因爲我不知道您正在顯示圖像的尺寸也沒有圖像的尺寸

我會建議你使用通用圖像裝載機庫(https://github.com/nostra13/Android-Universal-Image-Loader),這將解決所有上述問題。雖然我不確定它是否提供本地本地圖像加載功能,或者您是否需要擴展某個類以具備這種功能。


[編輯]

我不會推薦作爲滾動它會採取比你最初想象更多的時間自己的解決方案(相信我...)。但如果你真的想這樣做,你可以看看這個教程:http://codehenge.net/blog/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/

上面的教程解決#1 &#2,#爲3檢查:Strange out of memory issue while loading an image to a Bitmap object

+0

是的,你說得對@凱,我的列表很不穩定。假設我不想使用Universal Loader庫,我該如何處理上面列出的問題?我想: 1)創建一個單獨的線程,如果該項目超出列表範圍,則會被中斷。 2)我可以在getView之外創建一次位圖嗎? 3)我可以正確縮放所有圖像? 這可以接受嗎? – GVillani82

+0

@ Joseph82更新了答案,請注意,即使是教程也沒有做到這一點,因爲它不會取消視圖的上一次檢索圖像操作,當滾動速度非常快時會導致「閃爍圖像」artifects。所以我再次不親自推薦這個:P – Kai

+0

謝謝@凱。我想起初我會嘗試我的解決方案:我喜歡挑戰:)但是,然後我瘦我會用你建議的圖書館xD – GVillani82

1

首先,您需要一個像LruCache這樣的數據結構來存放正在創建的繪圖。

How can I be sure that my objects are correctly released?

在活動使用數據結構銷燬時,請確保該類的對象被設爲null或清除其內部對象。 (這會告訴gc該對象已準備好被清除(大多數情況下))。

在主線程上運行文件操作並不是最好的方法,因爲它會在listview滾動中引入干擾。嘗試在輔助線程中執行此操作。

+0

謝謝@ 66CLSjY你可以給我一些關於如何在ListView中使用LruCache的例子嗎? – GVillani82

+0

檢查出http://stackoverflow.com/questions/11623994/example-using-androids-lrucache和研究位圖。 – 66CLSjY