มันเป็นจุดสิ้นสุดของปี 2018 ดังนั้นสิ่งต่างๆจึงเปลี่ยนไป
ก่อนอื่น: เปิดแอปของคุณและเปิดแท็บ Android Profiler ใน Android Studio คุณจะเห็นจำนวนหน่วยความจำที่ใช้ไปคุณจะประหลาดใจ แต่สามารถจัดสรร RAM ได้จำนวนมาก
นอกจากนี้ที่นี่เป็นบทความที่ยอดเยี่ยมในเอกสารอย่างเป็นทางการพร้อมคำแนะนำโดยละเอียดเกี่ยวกับวิธีการใช้ Memory Profiler ซึ่งสามารถให้การจัดการหน่วยความจำของคุณในเชิงลึก
แต่ในกรณีส่วนใหญ่ Android Profiler ปกติของคุณจะเพียงพอสำหรับคุณ
โดยปกติแล้วแอปจะเริ่มต้นด้วยการจัดสรร RAM ขนาด 50Mb แต่จะกระโดดได้สูงถึง 90Mb ทันทีเมื่อคุณเริ่มโหลดรูปภาพในหน่วยความจำ เมื่อคุณเปิดกิจกรรมด้วย ViewPager พร้อมภาพถ่ายที่โหลดไว้ล่วงหน้า (3,5Mb แต่ละรายการ) คุณสามารถรับ 190Mb ได้อย่างง่ายดายในไม่กี่วินาที
แต่นี่ไม่ได้หมายความว่าคุณมีปัญหากับการจัดการหน่วยความจำ
คำแนะนำที่ดีที่สุดที่ฉันสามารถให้ได้ก็คือปฏิบัติตามแนวทางและแนวปฏิบัติที่ดีที่สุดใช้ไลบรารี่ชั้นนำสำหรับการโหลดรูปภาพ (Glide, Picasso) และคุณจะโอเค
แต่ถ้าคุณต้องการปรับแต่งบางสิ่งและคุณจำเป็นต้องรู้จำนวนหน่วยความจำที่คุณสามารถจัดสรรได้ด้วยตนเองคุณจะได้รับหน่วยความจำฟรีทั้งหมดและคำนวณสัดส่วนที่กำหนดไว้ล่วงหน้า (เป็น%) ในกรณีของฉันฉันต้องแคชรูปถ่ายที่ถอดรหัสในหน่วยความจำดังนั้นฉันไม่จำเป็นต้องถอดรหัสพวกเขาทุกครั้งที่ผู้ใช้เลื่อนผ่านรายการ
เพื่อจุดประสงค์นี้คุณสามารถใช้พร้อมที่จะใช้ระดับ LruCache เป็นคลาสแคชที่ติดตามจำนวนหน่วยความจำที่ออบเจ็กต์ของคุณจัดสรร (หรือจำนวนอินสแตนซ์) โดยอัตโนมัติและลบสิ่งที่เก่าที่สุดเพื่อเก็บข้อมูลล่าสุดตามประวัติการใช้งาน
นี่คือการสอนที่ดีเกี่ยวกับวิธีการใช้งาน
ในกรณีของฉันฉันสร้างแคช 2 อินสแตนซ์: สำหรับนิ้วหัวแม่มือและไฟล์แนบ ทำให้พวกเขาคงที่ด้วยการเข้าถึงซิงเกิลเพื่อให้พวกเขาทั่วโลกตลอดทั้งแอพ
คลาสแคช:
public class BitmapLruCache extends LruCache<Uri, byte[]> {
private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
private static BitmapLruCache thumbCacheInstance;
private static BitmapLruCache attachmentCacheInstance;
public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
if (thumbCacheInstance == null) {
int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
//L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
thumbCacheInstance = new BitmapLruCache(cacheSize);
return thumbCacheInstance;
} else {
return thumbCacheInstance;
}
}
public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
if (attachmentCacheInstance == null) {
int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
// L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
attachmentCacheInstance = new BitmapLruCache(cacheSize);
return attachmentCacheInstance;
} else {
return attachmentCacheInstance;
}
}
private BitmapLruCache(int maxSize) {
super(maxSize);
}
public void addBitmap(Uri uri, byte[] bitmapBytes) {
if (get(uri) == null && bitmapBytes != null)
put(uri, bitmapBytes);
}
public byte[] getBitmap(Uri uri) {
return get(uri);
}
@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
// The cache size will be measured in bytes rather than number of items.
return bitmapBytes.length;
}
}
นี่คือวิธีที่ฉันคำนวณ RAM ว่างที่มีอยู่และจำนวนเงินที่ฉันสามารถทำได้:
private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
final long maxMemory = Runtime.getRuntime().maxMemory();
//Use ... of available memory for List Notes thumb cache
return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}
และนี่คือวิธีที่ฉันใช้ในอะแดปเตอร์เพื่อรับรูปภาพแคช:
byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);
และฉันจะตั้งเป็นแคชในเธรดพื้นหลัง (AsyncTask ปกติ):
BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes);
แอพของฉันตั้งเป้าหมาย API 19+ ดังนั้นอุปกรณ์ไม่เก่าและ RAM ส่วนต่าง ๆ เหล่านี้ดีพอสำหรับแคชในกรณีของฉัน (1% และ 3%)
เรื่องสนุก: Android ไม่มี API หรือแฮ็กอื่น ๆ ที่จะได้รับจำนวนหน่วยความจำที่จัดสรรให้แอปของคุณมันคำนวณได้ทันทีจากปัจจัยหลายประการ
PS ฉันใช้ฟิลด์คลาสคงที่เพื่อเก็บแคช แต่ตามแนวทาง Android ล่าสุดแนะนำให้ใช้ส่วนประกอบสถาปัตยกรรม ViewModelสำหรับจุดประสงค์นั้น