现在是 2018 年底,所以情况发生了变化。
首先:运行您的应用并在 Android Studio 中打开 Android Profiler 选项卡。您会看到它消耗了多少内存,您会感到惊讶,但它可以分配大量 RAM。
此外,官方文档中还有一篇很棒的文章,其中包含有关如何使用 Memory Profiler 的详细说明,它可以让您深入了解内存管理。
但在大多数情况下,您的常规 Android Profiler 对您来说就足够了。
通常,一个应用程序从 50Mb 的 RAM 分配开始,但当您开始在内存中加载一些照片时,它会立即跃升至 90Mb。当您使用带有预加载照片(每张 3.5Mb)的 ViewPager 打开 Activity 时,您可以在几秒钟内轻松获得 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 或其他 hack 来获取分配给您的应用程序的内存量,它是根据各种因素动态计算的。
PS 我正在使用静态类字段来保存缓存,但根据最新的 Android 指南,它建议为此目的使用ViewModel 架构组件。