现在已经是2018年末,情况有所改变。
首先:运行你的应用,并在Android Studio中打开Android Profiler选项卡。
你将会看到它消耗了多少内存,你会惊讶地发现它可以分配很多RAM。
此外,在官方文档中 这里有一篇很棒的文章 ,详细介绍了如何使用Memory Profiler来深入了解你的内存管理。
但在大多数情况下,普通的Android Profiler就足够了。
通常情况下,一个应用程序开始时会分配50Mb的RAM,但在你开始加载一些照片到内存时,它会立即跳到90Mb。当你打开一个ViewPager并预加载带有相片(每个3.5Mb)的Activity时,你可以轻易地在几秒钟内得到190Mb。
但这并不意味着你存在内存管理问题。
我能给出的最好的建议就是遵循指南和最佳实践,使用顶级图像加载库(Glide、Picasso),你就没问题了。
但如果你需要调整一些东西,并且你真的需要知道你可以手动分配多少内存,你可以获取总空闲内存并计算出其中预先确定的部分(以%)。
在我的情况下,我需要将解密后的照片缓存在内存中,这样每当用户滑动列表时就不需要再解密它们了。
为此,你可以使用现成的LruCache类。这是一个缓存类,它会自动跟踪对象分配的内存量(或实例数量),并删除最老的对象以保持最近的使用历史。
这里有一个很棒的教程,介绍如何使用它。
在我的情况下,我创建了两个缓存实例:用于缩略图和附件。
用单例访问方法使它们静态化,这样它们就可以在整个应用程序中全局可用。
缓存类:
public class BitmapLruCache extends LruCache<Uri, byte[]> {
private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f;
private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;
private static BitmapLruCache thumbCacheInstance;
private static BitmapLruCache attachmentCacheInstance;
public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
if (thumbCacheInstance == null) {
int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
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);
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) {
return bitmapBytes.length;
}
}
这是我计算可用空闲RAM及可以利用的容量的方法:
private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
final long maxMemory = Runtime.getRuntime().maxMemory();
return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}
以下是我在Adapter中使用它来获取缓存图像的方法:
byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri)
我如何在后台线程(常规AsyncTask)中将其设置到缓存中:
BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes)
我的应用程序针对API 19+,因此设备不算老旧,可用的RAM缓存量在我这种情况下足够(为1%和3%)。
有趣的事实:Android没有任何API或其他技巧来获取分配给您的应用程序的内存量,它是根据各种因素即时计算出来的。
P.S. 我正在使用静态类字段来保存缓存,但根据最新的Android指南,建议使用ViewModel architecture component来完成此目的。