2018年末なので、状況は変わりました。
まず、アプリを実行し、Android StudioでAndroid Profilerタブを開きます。どれだけのメモリを消費するかがわかります。驚かれることでしょうが、大量のRAMを割り当てることができます。
また、メモリ管理の詳細を確認できるMemory Profilerの使用方法の詳細な手順が記載された公式ドキュメントのすばらしい記事もここにあります。
しかし、ほとんどの場合、通常のAndroidプロファイラーで十分です。
通常、アプリは50MbのRAM割り当てで開始しますが、メモリへの写真の読み込みを開始すると、すぐに最大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アーキテクチャコンポーネントを使用することをお勧めします。