java.lang.OutOfMemoryError: ขนาดบิตแมปเกินงบประมาณ VM - Android


159

ฉันพัฒนาแอพพลิเคชั่นที่ใช้รูปภาพจำนวนมากบน Android

แอปพลิเควิ่งครั้งเดียวเติมข้อมูลบนหน้าจอ ( Layouts, Listviews, Textviews, ImageViewsฯลฯ ) และผู้ใช้อ่านข้อมูล

ไม่มีภาพเคลื่อนไหวไม่มีเอฟเฟกต์พิเศษหรืออะไรก็ตามที่สามารถเติมหน่วยความจำได้ บางครั้ง drawables สามารถเปลี่ยนได้ บางแหล่งข้อมูลเป็น Android และบางส่วนเป็นไฟล์ที่บันทึกในโฟลเดอร์ใน SDCARD

จากนั้นผู้ใช้จะออก ( onDestroyวิธีการดำเนินการและแอพยังคงอยู่ในหน่วยความจำโดย VM) จากนั้นในบางครั้งผู้ใช้จะเข้าสู่อีกครั้ง

ทุกครั้งที่ผู้ใช้ป้อนไปยังแอปที่ฉันสามารถดูหน่วยความจำที่เติบโตมากขึ้นเรื่อย ๆ java.lang.OutOfMemoryErrorจนกว่าผู้ใช้จะได้รับ

ดังนั้นวิธีที่ดีที่สุด / ถูกต้องในการจัดการภาพจำนวนมากคืออะไร?

ฉันควรใส่วิธีคงที่เพื่อไม่ให้โหลดตลอดเวลาหรือไม่ ฉันต้องทำความสะอาดเลย์เอาต์หรือรูปภาพที่ใช้ในเลย์เอาต์ด้วยวิธีพิเศษหรือไม่?


4
วิธีนี้อาจช่วยได้หากคุณมีการเปลี่ยนแปลงจำนวนมาก มันใช้งานได้ตั้งแต่ฉันทำโปรแกรมด้วยตัวเอง :) androidactivity.wordpress.com/2011/09/24/…

คำตอบ:


72

ดูเหมือนว่าคุณมีหน่วยความจำรั่ว ปัญหาไม่ได้จัดการภาพหลายภาพเพราะภาพของคุณไม่ได้ถูกจัดสรรคืนเมื่อกิจกรรมของคุณถูกทำลาย

เป็นการยากที่จะบอกว่าทำไมสิ่งนี้ถึงไม่ดูรหัสของคุณ อย่างไรก็ตามบทความนี้มีเคล็ดลับที่อาจช่วยได้:

http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html

โดยเฉพาะอย่างยิ่งการใช้ตัวแปรแบบสแตติกมีแนวโน้มที่จะทำให้สิ่งเลวร้ายลงไม่ดีขึ้น คุณอาจต้องเพิ่มรหัสที่ลบการเรียกกลับเมื่อแอปพลิเคชันของคุณออกใหม่ - แต่อีกครั้งมีข้อมูลไม่เพียงพอที่จะพูดได้อย่างแน่นอน


8
นี่เป็นเรื่องจริงและยังมีรูปภาพจำนวนมาก (และไม่ใช่การรั่วไหลของหน่วยความจำ) สามารถทำให้ outOfMemory ได้ด้วยเหตุผลหลายประการเช่นมีแอพอื่น ๆ มากมายที่กำลังทำงานอยู่การกระจายตัวของหน่วยความจำ ฯลฯ ฉันเรียนรู้ว่าเมื่อทำงานกับรูปภาพจำนวนมาก อย่างเป็นระบบเหมือนกับการทำแบบเดียวกันเสมอ หากคุณได้รับเช่นวันละครั้งหรือบางสิ่งบางอย่างมันเป็นเพราะคุณอยู่ใกล้ขีด จำกัด มากเกินไป คำแนะนำของฉันในกรณีนี้คือพยายามลบบางสิ่งและลองอีกครั้ง หน่วยความจำภาพยังอยู่นอกหน่วยความจำฮีปดังนั้นให้ระวังทั้งคู่
Daniel Benedykt

15
หากคุณสงสัยว่ามีหน่วยความจำรั่ววิธีที่รวดเร็วในการตรวจสอบการใช้ฮีปคือผ่านคำสั่ง adb shell dumpsys คำสั่ง meminfo หากคุณเห็นการใช้ฮีปเพิ่มขึ้นในช่วงไม่กี่ gc (แถวบันทึก GC_ * ใน logcat) คุณค่อนข้างมั่นใจว่าคุณมีการรั่วไหล จากนั้นสร้างกองการถ่ายโอนข้อมูล (หรือหลายครั้งในเวลาที่แตกต่างกัน) ผ่าน adb หรือ DDMS และวิเคราะห์โดยใช้เครื่องมือต้นไม้ Dominator บน Eclipse MAT ในไม่ช้าคุณควรจะพบว่าวัตถุใดมีฮีปที่คงอยู่ตลอดเวลา นั่นคือความจำของคุณรั่วไหล ฉันเขียนบทความที่มีรายละเอียดเพิ่มเติมที่นี่: macgyverdev.blogspot.com/2011/11/…
Johan Norén

98

หนึ่งในข้อผิดพลาดที่พบบ่อยที่สุดที่ฉันพบในการพัฒนา Android Apps คือข้อผิดพลาด“ java.lang.OutOfMemoryError: บิตแมปขนาดเกินงบประมาณ VM” ฉันพบข้อผิดพลาดนี้บ่อยครั้งในกิจกรรมที่ใช้บิตแมปจำนวนมากหลังจากเปลี่ยนการวางแนว: กิจกรรมถูกทำลายสร้างขึ้นอีกครั้งและโครงร่าง“ พองตัว” จาก XML ซึ่งใช้หน่วยความจำ VM สำหรับบิตแมป

บิตแมปในโครงร่างกิจกรรมก่อนหน้านี้ไม่ได้ถูกจัดสรรอย่างเหมาะสมโดยตัวรวบรวมขยะเพราะพวกเขามีการอ้างอิงข้ามกับกิจกรรมของพวกเขา หลังจากการทดลองหลายครั้งฉันพบวิธีแก้ปัญหาที่ค่อนข้างดีสำหรับปัญหานี้

ก่อนอื่นให้ตั้งค่าแอตทริบิวต์“ id” ในมุมมองพาเรนต์ของโครงร่าง XML ของคุณ:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:id="@+id/RootView"
     >
     ...

จากนั้นในonDestroy() วิธีการของการเคลื่อนไหวของคุณเรียกวิธีการผ่านการอ้างอิงไปยังผู้ปกครองดูแล้วทำunbindDrawables()System.gc()

    @Override
    protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
    }

    private void unbindDrawables(View view) {
        if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
        ((ViewGroup) view).removeAllViews();
        }
    }

unbindDrawables()วิธีนี้สำรวจแผนผังมุมมองแบบวนซ้ำและ:

  1. ลบการเรียกกลับใน drawable พื้นหลังทั้งหมด
  2. ลบชายด์ในทุกกลุ่มการดู

10
ยกเว้น ... java.lang.UnsupportedOperationException: removeAllViews () ไม่ได้รับการสนับสนุนใน AdapterView

ขอบคุณสิ่งนี้จะช่วยลดขนาดฮีปของฉันลงอย่างมากเนื่องจากฉันมี drawable จำนวนมาก ... @GJTorikian สำหรับสิ่งที่เพิ่งลองมาดูที่ removeAllViews () คลาสย่อย ViewGroup ส่วนใหญ่ทำงานได้ดี
Eric Chen

5
หรือเพียงแค่เปลี่ยนเงื่อนไข: if (ดูอินสแตนซ์ของ ViewGroup &&! (ดูอินสแตนซ์ของ AdapterView))
Anke

2
@ Adam Varhegyi คุณสามารถเรียกใช้ฟังก์ชันเดียวกันนี้ได้อย่างชัดเจนสำหรับมุมมองแกลเลอรีใน onDestroy ชอบ unbindDrawables (galleryView); หวังว่านี่จะใช้งานได้สำหรับคุณ ...
hp.android

1
ระวังstackoverflow.com/questions/8405475/…ของ gotcha ทั้งสองนี้และstackoverflow.com/questions/4486034/…
max4ever

11

เพื่อหลีกเลี่ยงปัญหานี้คุณสามารถใช้วิธีพื้นเมืองBitmap.recycle()ก่อนที่nullไอเอ็นจีBitmapวัตถุ (หรือการตั้งค่าอื่น) ตัวอย่าง:

public final void setMyBitmap(Bitmap bitmap) {
  if (this.myBitmap != null) {
    this.myBitmap.recycle();
  }
  this.myBitmap = bitmap;
}

และต่อไปคุณสามารถเปลี่ยนโดยไม่ต้องmyBitmapโทรSystem.gc()เช่น:

setMyBitmap(null);    
setMyBitmap(anotherBitmap);

1
สิ่งนี้จะไม่ทำงานหากพยายามเพิ่มองค์ประกอบเหล่านั้นลงใน listview คุณมีข้อเสนอแนะเกี่ยวกับเรื่องนี้ไหม?
Rafael Sanches

@ddmytrenko คุณกำลังรีไซเคิลภาพก่อนที่จะกำหนด นั่นจะป้องกันพิกเซลไม่ได้
IgorGanapolsky

8

ฉันเจอปัญหานี้แล้ว ฮีปมีขนาดค่อนข้างเล็กดังนั้นรูปภาพเหล่านี้สามารถควบคุมได้ค่อนข้างเร็วในหน่วยความจำ วิธีหนึ่งคือการให้คำแนะนำขยะเก็บในหน่วยความจำเก็บรวบรวมเกี่ยวกับบิตแมปโดยเรียกวิธีการรีไซเคิลของ

นอกจากนี้วิธีการ onDestroy ไม่รับประกันว่าจะได้รับการเรียก คุณอาจต้องการย้ายตรรกะนี้ / ล้างข้อมูลลงในกิจกรรม onPause ตรวจสอบไดอะแกรมกิจกรรม / ตารางวงจรชีวิตในหน้านี้สำหรับข้อมูลเพิ่มเติม


ขอบคุณสำหรับข้อมูล. ฉันกำลังจัดการ Drawables ทั้งหมดไม่ใช่ Bitmaps ดังนั้นฉันจึงไม่สามารถเรียก Recycle ข้อเสนอแนะอื่น ๆ สำหรับ drawable? ขอบคุณ Daniel
Daniel Benedykt

ขอบคุณสำหรับonPauseคำแนะนำ ฉันใช้แท็บ 4 แท็บที่มีBitmapรูปภาพอยู่ทั้งหมดดังนั้นการทำลายกิจกรรมอาจไม่เกิดขึ้นเร็วเกินไป (หากผู้ใช้เรียกดูแท็บทั้งหมด)
Azurespot

7

คำอธิบายนี้อาจช่วยได้: http://code.google.com/p/android/issues/detail?id=8488#c80

"เคล็ดลับเร็ว:

1) ไม่เคยเรียก System.gc () ด้วยตัวคุณเอง สิ่งนี้ได้รับการเผยแพร่เป็นการแก้ไขที่นี่และมันไม่ทำงาน อย่าทำมัน. หากคุณสังเกตเห็นในคำอธิบายของฉันก่อนที่จะรับ OutOfMemoryError JVM จะรันคอลเล็กชันขยะดังนั้นจึงไม่มีเหตุผลที่จะทำอีกครั้ง (ทำให้โปรแกรมของคุณช้าลง) ทำสิ่งใดสิ่งหนึ่งในตอนท้ายของกิจกรรมของคุณเป็นเพียงการปกปิดปัญหา มันอาจทำให้บิตแมปที่จะใส่คิว finalizer เร็วขึ้น แต่ไม่มีเหตุผลที่คุณไม่ได้เรียกเพียงแค่รีไซเคิลในแต่ละบิตแมปแทน

2) โทรรีไซเคิล () บนบิตแมปที่คุณไม่ต้องการอีกต่อไป อย่างน้อยที่สุดใน onDestroy กิจกรรมของคุณจะต้องผ่านและรีไซเคิลบิตแมปทั้งหมดที่คุณใช้ นอกจากนี้หากคุณต้องการให้รวบรวมอินสแตนซ์บิตแมปจาก dalvik heap เร็วขึ้นจะไม่เป็นการยากที่จะลบการอ้างอิงใด ๆ ไปยังบิตแมป

3) การโทรรีไซเคิล () จากนั้น System.gc () อาจไม่สามารถลบบิตแมปออกจากกอง Dalvik อย่ากังวลเกี่ยวกับเรื่องนี้ recycle () ทำงานของมันและปลดปล่อยหน่วยความจำดั้งเดิมมันใช้เวลาสักครู่เพื่อทำตามขั้นตอนที่ฉันระบุไว้ก่อนหน้านี้เพื่อลบบิตแมปออกจากกอง Dalvik นี่ไม่ใช่เรื่องใหญ่เพราะหน่วยความจำดั้งเดิมขนาดใหญ่ฟรีอยู่แล้ว!

4) มักจะถือว่ามีข้อผิดพลาดในกรอบสุดท้าย Dalvik กำลังทำสิ่งที่ควรทำ มันอาจจะไม่ใช่สิ่งที่คุณคาดหวังหรือสิ่งที่คุณต้องการ แต่มันเป็นวิธีการทำงาน "


5

ฉันมีปัญหาเดียวกันแน่นอน หลังจากการทดสอบสองสามครั้งฉันพบว่าข้อผิดพลาดนี้ปรากฏขึ้นสำหรับการปรับขนาดภาพใหญ่ ฉันลดขนาดภาพและปัญหาหายไป

PS ตอนแรกฉันพยายามลดขนาดภาพโดยไม่ลดขนาดภาพลง นั่นไม่ได้หยุดข้อผิดพลาด


4
คุณช่วยโพสต์โค้ดว่าคุณปรับขนาดภาพได้อย่างไรฉันกำลังประสบปัญหาเดียวกันและฉันคิดว่านี่อาจช่วยแก้ปัญหาได้ ขอบคุณ!
Gligor

@Gix - ฉันเชื่อว่าเขาหมายความว่าเขาต้องลดขนาดของภาพก่อนที่จะนำพวกเขาเข้าสู่ทรัพยากรของโครงการจึงลดรอยความทรงจำของ drawable สำหรับสิ่งนี้คุณควรใช้โปรแกรมแก้ไขภาพที่คุณเลือก ฉันชอบ pixlr.com
Kyle Clegg

5

ประเด็นต่อไปนี้ช่วยฉันได้มากจริงๆ อาจมีประเด็นอื่นเช่นกัน แต่สิ่งเหล่านี้สำคัญมาก:

  1. ใช้บริบทแอปพลิเคชัน (แทน activity.this) ที่เป็นไปได้
  2. หยุดและปล่อยเธรดของคุณในวิธีการ onPause ()
  3. ปล่อยมุมมอง / การโทรกลับของคุณในวิธีการ onDestroy ()

4

ฉันขอแนะนำวิธีที่สะดวกในการแก้ปัญหานี้ เพียงกำหนดแอตทริบิวต์ "android: configChanges" ตามที่ระบุไว้ใน Mainfest.xml สำหรับกิจกรรมที่มีข้อผิดพลาดของคุณ แบบนี้:

<activity android:name=".main.MainActivity"
              android:label="mainActivity"
              android:configChanges="orientation|keyboardHidden|navigation">
</activity>

ทางออกแรกที่ฉันมอบให้ได้ลดความถี่ของความผิดพลาดของ OOM ลงเหลือน้อย แต่มันไม่ได้แก้ปัญหาโดยสิ้นเชิง แล้วฉันจะให้ทางออกที่ 2:

ตามรายละเอียดของ OOM ฉันใช้หน่วยความจำรันไทม์มากเกินไป ดังนั้นฉันจึงลดขนาดภาพเป็น ~ / res / drawable ของโครงการของฉัน เช่นรูปภาพที่มีคุณสมบัติไม่เหมาะสมซึ่งมีความละเอียด 128X128 สามารถปรับขนาดเป็น 64x64 ซึ่งเหมาะสำหรับการใช้งานของฉันเช่นกัน และหลังจากที่ฉันทำเช่นนั้นด้วยกองรูปภาพข้อผิดพลาด OOM จะไม่เกิดขึ้นอีก


1
สิ่งนี้ทำงานได้เพราะคุณหลีกเลี่ยงการรีสตาร์ทแอพของคุณ ดังนั้นจึงไม่ได้เป็นทางออกมากเพราะเป็นการหลีกเลี่ยง แต่บางครั้งนั่นคือทั้งหมดที่คุณต้องการ และวิธีการเริ่มต้น onConfigurationChanged () ในกิจกรรมจะพลิกการวางแนวของคุณให้คุณดังนั้นหากคุณไม่ต้องการการเปลี่ยนแปลง UI ใด ๆ เพื่อปรับให้เข้ากับทิศทางที่แตกต่างกันอย่างแท้จริงคุณอาจพอใจกับผลลัพธ์อย่างสมบูรณ์ ระวังสิ่งอื่น ๆ ที่สามารถรีสตาร์ทคุณได้ คุณอาจต้องการใช้สิ่งนี้: android: configChanges = "keyboardHidden | ปฐมนิเทศ | แป้นพิมพ์ | locale | mcc | mnc | หน้าจอสัมผัส | screenLayout | fontScale"
Carl

3

ฉันก็รู้สึกผิดหวังกับข้อผิดพลาด outofmemory และใช่ฉันก็พบว่าข้อผิดพลาดนี้ปรากฏขึ้นมากเมื่อปรับขนาดภาพ ตอนแรกฉันพยายามสร้างขนาดภาพสำหรับความหนาแน่นทั้งหมด แต่ฉันพบว่าขนาดของแอปเพิ่มขึ้นอย่างมาก ดังนั้นตอนนี้ฉันแค่ใช้ภาพเดียวสำหรับความหนาแน่นทั้งหมดและปรับขนาดภาพของฉัน

แอปพลิเคชันของฉันจะโยนข้อผิดพลาดจากหน่วยความจำทุกครั้งที่ผู้ใช้เปลี่ยนจากกิจกรรมหนึ่งไปอีกกิจกรรม การตั้งค่า drawables ของฉันเป็นโมฆะและเรียก System.gc () ไม่ทำงานและไม่ได้ทำการรีไซเคิล bitmapDrawables ของฉันด้วย getBitMap () รีไซเคิล () Android จะยังคงโยนข้อผิดพลาด outofmemory ด้วยวิธีแรกและมันจะโยนข้อความแสดงข้อผิดพลาดผ้าใบทุกครั้งที่มันพยายามใช้บิตแมปรีไซเคิลกับวิธีที่สอง

ฉันใช้วิธีที่สาม ฉันตั้งค่ามุมมองทั้งหมดเป็น null และพื้นหลังเป็นสีดำ ฉันจะล้างข้อมูลนี้ในวิธีการ onStop () ของฉัน นี่เป็นวิธีการที่เรียกใช้ทันทีที่มองไม่เห็นกิจกรรมอีกต่อไป หากคุณใช้วิธีการ onPause () ผู้ใช้จะเห็นพื้นหลังสีดำ ไม่เหมาะ สำหรับการทำในวิธี onDestroy () ไม่มีการรับประกันว่ามันจะถูกเรียก

เพื่อป้องกันไม่ให้หน้าจอสีดำเกิดขึ้นหากผู้ใช้กดปุ่มย้อนกลับบนอุปกรณ์ฉันจะโหลดกิจกรรมในเมธอด onRestart () โดยการเรียกใช้ startActivity (getIntent ()) และจากนั้นเสร็จสิ้น ()

หมายเหตุ: ไม่จำเป็นต้องเปลี่ยนพื้นหลังเป็นสีดำ


1

ไม่ควรเรียกใช้วิธีการ BitmapFactory.decode * ที่กล่าวถึงในบทเรียนการโหลดบิตแมปขนาดใหญ่อย่างมีประสิทธิภาพบนเธรด UI หลักหากข้อมูลต้นฉบับถูกอ่านจากดิสก์หรือตำแหน่งเครือข่าย (หรือแหล่งอื่น ๆ นอกเหนือจากหน่วยความจำจริงๆ) เวลาที่ข้อมูลนี้ใช้ในการโหลดไม่สามารถคาดการณ์ได้และขึ้นอยู่กับปัจจัยหลายประการ (ความเร็วในการอ่านจากดิสก์หรือเครือข่ายขนาดของภาพกำลังของ CPU ฯลฯ ) หากหนึ่งในภารกิจเหล่านี้บล็อกเธรด UI ระบบจะแจ้งสถานะแอปพลิเคชันของคุณว่าไม่ตอบสนองและผู้ใช้มีตัวเลือกในการปิด (ดูที่การออกแบบเพื่อการตอบสนองสำหรับข้อมูลเพิ่มเติม)


0

ดีฉันลองทุกอย่างที่ฉันพบบนอินเทอร์เน็ตและก็ไม่ทำงานเลย การโทร System.gc () จะลดความเร็วของแอพลงเท่านั้น การรีไซเคิลบิตแมปใน onDestroy ไม่ได้ผลสำหรับฉันเช่นกัน

สิ่งเดียวที่ทำงานได้ในขณะนี้คือการมีรายการแบบคงที่ของบิตแมปทั้งหมดเพื่อให้บิตแมปอยู่รอดหลังจากรีสตาร์ท และเพียงแค่ใช้บิตแมปที่บันทึกไว้แทนที่จะสร้างใหม่ทุกครั้งที่มีการรีสตาร์ท

ในกรณีของฉันรหัสดูเหมือนดังนี้:

private static BitmapDrawable currentBGDrawable;

if (new File(uriString).exists()) {
    if (!uriString.equals(currentBGUri)) {
        freeBackground();
        bg = BitmapFactory.decodeFile(uriString);

        currentBGUri = uriString;
        bgDrawable = new BitmapDrawable(bg);
        currentBGDrawable = bgDrawable;
    } else {
        bgDrawable = currentBGDrawable;
    }
}

สิ่งนี้จะไม่รั่วบริบทของคุณ? (ข้อมูลกิจกรรม)
Rafael Sanches

0

ฉันมีปัญหาเดียวกันเพียงแค่เปลี่ยนภาพพื้นหลังด้วยขนาดที่เหมาะสม ฉันได้ผลลัพธ์ที่ดีขึ้นด้วยการตั้งค่า ImageView เป็น null ก่อนที่จะใส่ภาพใหม่

ImageView ivBg = (ImageView) findViewById(R.id.main_backgroundImage);
ivBg.setImageDrawable(null);
ivBg.setImageDrawable(getResources().getDrawable(R.drawable.new_picture));

0

FWIW นี่คือบิตแมปแคชที่มีน้ำหนักเบาที่ฉันเขียนและใช้เวลาสองสามเดือน ไม่ใช่เสียงระฆังและเสียงนกหวีดโปรดอ่านโค้ดก่อนใช้งาน

/**
 * Lightweight cache for Bitmap objects. 
 * 
 * There is no thread-safety built into this class. 
 * 
 * Note: you may wish to create bitmaps using the application-context, rather than the activity-context. 
 * I believe the activity-context has a reference to the Activity object. 
 * So for as long as the bitmap exists, it will have an indirect link to the activity, 
 * and prevent the garbaage collector from disposing the activity object, leading to memory leaks. 
 */
public class BitmapCache { 

    private Hashtable<String,ArrayList<Bitmap>> hashtable = new Hashtable<String, ArrayList<Bitmap>>();  

    private StringBuilder sb = new StringBuilder(); 

    public BitmapCache() { 
    } 

    /**
     * A Bitmap with the given width and height will be returned. 
     * It is removed from the cache. 
     * 
     * An attempt is made to return the correct config, but for unusual configs (as at 30may13) this might not happen.  
     * 
     * Note that thread-safety is the caller's responsibility. 
     */
    public Bitmap get(int width, int height, Bitmap.Config config) { 
        String key = getKey(width, height, config); 
        ArrayList<Bitmap> list = getList(key); 
        int listSize = list.size();
        if (listSize>0) { 
            return list.remove(listSize-1); 
        } else { 
            try { 
                return Bitmap.createBitmap(width, height, config);
            } catch (RuntimeException e) { 
                // TODO: Test appendHockeyApp() works. 
                App.appendHockeyApp("BitmapCache has "+hashtable.size()+":"+listSize+" request "+width+"x"+height); 
                throw e ; 
            }
        }
    }

    /**
     * Puts a Bitmap object into the cache. 
     * 
     * Note that thread-safety is the caller's responsibility. 
     */
    public void put(Bitmap bitmap) { 
        if (bitmap==null) return ; 
        String key = getKey(bitmap); 
        ArrayList<Bitmap> list = getList(key); 
        list.add(bitmap); 
    }

    private ArrayList<Bitmap> getList(String key) {
        ArrayList<Bitmap> list = hashtable.get(key);
        if (list==null) { 
            list = new ArrayList<Bitmap>(); 
            hashtable.put(key, list); 
        }
        return list;
    } 

    private String getKey(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Config config = bitmap.getConfig();
        return getKey(width, height, config);
    }

    private String getKey(int width, int height, Config config) {
        sb.setLength(0); 
        sb.append(width); 
        sb.append("x"); 
        sb.append(height); 
        sb.append(" "); 
        switch (config) {
        case ALPHA_8:
            sb.append("ALPHA_8"); 
            break;
        case ARGB_4444:
            sb.append("ARGB_4444"); 
            break;
        case ARGB_8888:
            sb.append("ARGB_8888"); 
            break;
        case RGB_565:
            sb.append("RGB_565"); 
            break;
        default:
            sb.append("unknown"); 
            break; 
        }
        return sb.toString();
    }

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.