android最適化(二)---Appデバッグメモリ漏洩の画像Bitmap編


android最適化(二)---Appデバッグメモリ漏洩の画像Bitmap編
Android最適化では、アプリケーションリソースを削減し、apkのサイズを減らすだけでなく、メモリの漏洩を効果的に回避し、アプリケーションの最適化を実現します.
aできるだけ画像を使わない
お客様は、アプリケーションの表示効果を設計する際に、インタフェースの美化の目的を達成するために.多くの場所で画像が使われており、画面全体の背景に画像が使われているアプリケーションもあります.画像の大量使用は、アプリケーションのAPKのサイズが大きくなるだけでなく、アプリケーションが表示するメモリも大きくなります.
インタフェースをデザインするときは、できるだけ色や9 png画像を多く使ってください.背景として純色の画像を設定すると、色で代用できます.
ps:色を優先し、9 pngは使えないので、最後に画像を使うことを考えます.
 
b Bitmapの効率的な使用  
1).圧縮Bitmap
  画像の画素が大きすぎる場合、BitmapFactoryクラスの方法でBitmapをインスタンス化する過程で、8 Mより大きいメモリ空間が必要になると、必ずOutOfMemory異常が発生します.この時はどうすればいいですか?この場合、画像を縮小して、画像のロード中のメモリの使用を減らし、異常の発生を避けることができます.
       BitmapFactoryは、複数のリソースからBitmap(ビットマップ)オブジェクトを作成するためのいくつかの復号方法(decodeByteArray()、decodeFile()、decodeResource()など)を提供します.あなたの画像データソースに基づいて最適な復号方法を選択することができます.それぞれの復号方式には追加の特徴があり、BitmapFactory.Optionsクラスで復号方法を指定できます.
1
BitmapFactory.Options options = new BitmapFactory.Options();
2
options.inJustDecodeBounds = true;
3
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
4
int imageHeight = options.outHeight;
5
int imageWidth = options.outWidth;
6
String imageType = options.outMimeType;
 //画像の幅と高さを印刷
 Log.d("example", opts.outWidth + ","+ opts.outHeight);
---画像を復号する前に、画像のサイズをチェックします.inJustDecodeBoundsプロパティをtrueに設定すると、メモリ割り当てを回避できます.返されるbitmapオブジェクトはnullですが、outWidth、outHeight、outMimeTypeを設定できます.このテクノロジーでは、Bitmap(メモリの割り当て)を作成する前に、画像のサイズとタイプを読み取ることができます.画像リソースのサイズが予見可能で、使用可能なメモリに余裕があると確信していない限り.
---BitmapFactory.Optionsを使用してinSampleSizeを設定すると、画像を縮小できます.属性値inSampleSizeは、サムネイルサイズが元のピクチャサイズの数分の1であることを示します.すなわち、この値が2であれば、取り出したサムネイルの幅と高さはいずれも元のピクチャの1/2であり、ピクチャの大きさは元のピクチャの1/4である.
---実際のプロジェクトでは、上記のコードを利用して、画像の実際の幅と高さを取得し、縮小する必要があるかどうかを判断することができます.縮小する必要がない場合は、inSampleSizeの値を1に設定します.縮小が必要な場合は、inSampleSizeの値を動的に計算して設定し、画像を縮小します.BitmapFactoryのdecodeFile()などを使用してBitmapオブジェクトをインスタンス化する前に、opts.inJustDecodeBoundをfalseに戻すことを忘れないでください.そうでなければ取得されたbitmapオブジェクトはnullです.
経験の共有:
もしプログラムの画像の出所がすべてパッケージの中の資源であるならば、あるいは自分のサーバーの上の画像で、画像の大きさは開発者が調整することができるので、それでは一般的に、使う画像が大きすぎないことに注意するだけで、しかもコードの品質に注意して、直ちにBitmapの対象を回収して、OutOfMemoryの異常な発生を避けることができます.
プログラムの画像が外部から来ている場合は、OutOfMemoryの発生に特に注意する必要があります.1つは、ロードされた画像が大きい場合は、まず縮小する必要があります.もう1つは、プログラムCrashを回避するために異常をキャプチャする必要があります.
 
2)Bitmapキャッシュ
Bitmap(ビットマップ)をUIインタフェースにロードするのは簡単ですが、一度に大量にロードすると複雑になります.ほとんどの場合(ListView、GridView、またはViewPagerのようなコンポーネント)、画面上のピクチャおよびすぐに画面にスクロールして表示されるピクチャの総量は、本質的に制限されない. このようなコンポーネントは、サブビューが画面から移動するとビューの回収が行われ、メモリの使用は保持されます.しかし、長期的に生存する参照を残さないと、ゴミ回収器もロードしたBitmapを解放します.これはもちろんですが、スムーズで高速にロードされたUIを維持するためには、画像が画面に戻ったときに再処理しないようにしてください.メモリとハードディスク(HDD)キャッシュを使用すると、通常、この問題を解決できます.キャッシュを使用すると、コンポーネントが画像をすばやくロードして処理できます.
メモリキャッシュを使用して、  貴重なアプリケーションメモリを犠牲にする代わりに、メモリキャッシュは迅速なBitmapアクセスを提供します.LruCacheクラス(Support LibraryでAPIを取得およびサポート可能 Level 4以上、すなわち1.6以上)は、最近参照されたオブジェクトを強い参照のLinkedHashMapに格納し、キャッシュが指定したサイズを超えた後、最近あまり使用されていないオブジェクトを解放するキャッシュBitmapタスクとして非常に適しています.
 注:以前は非常にポピュラーなメモリキャッシュ実装がSoftReference(ソフトリファレンス)またはWeakReference(弱リファレンス)のBitmapキャッシュスキームであったが、現在は推奨されていない.Android 2.3バージョン(API Level 9)から、ゴミ回収器はソフト/弱参照の回収に重点を置いており、上記のスキームはかなり無効である.また、Android 3.0(API Level 11)以前のバージョンでは、Bitmapのバックアップデータがローカルメモリに直接格納され、予測不可能な方法でメモリから解放され、プログラムがメモリ制限を超えてクラッシュする可能性が高い.
 
3)Bitmapの即時回収
Androidアプリで最もメモリを消費するのは画像リソースです.ごみの回収はシステムでスケジューリングされていますが、Bitmapのメモリ自動回収メカニズムはそれほど理想的ではありません.Bitmapオブジェクトがメモリを占有している場合は、使用されていない場合は、Bitmap.recycle()メソッドを呼び出してアクティブに回収することが望ましい.
//          
if(bitmap != null && !bitmap.isRecycled()){ 
        //       null
        bitmap.recycle(); 
        bitmap = null; 
} 
System.gc();

上記のコードから分かるように、bitmap.recycle()メソッドは、Bitmapが消費するメモリを回収し、bitmapを空にし、最後にSystem.gc()を使用してシステムのゴミ回収器を呼び出して回収し、ゴミ回収器にできるだけ早く回収するように通知することができる.ここで注意しなければならないのは、System.gc()を呼び出すことは、回収プロセスを直ちに開始することを保証するものではなく、回収の到来を速めるためである.
recycle()メソッドを呼び出して回収する方法がわかりましたが、Bitmapのメモリをいつ解放するのが適切ですか?一般に,コードがBitmapオブジェクトを使用する必要がなくなり,解放される.メモリを解放すると、Bitmapオブジェクトは使用できなくなり、再使用すると例外が放出されます.だから、使わないときに解放されることを保証しなければなりません.たとえば、あるActivityでBitmapを使用する場合、ActivityのonStop()またはonDestroy()メソッドで回収できます.
4)異常捕捉
Bitmapはメモリを食べる大戸なので、Bitmapメモリを割り当てるときにOutOfMemory異常が発生した後にCrashが落ちるのを避けるためには、Bitmap部分のコードをインスタンス化することに特に注意する必要があります.通常、Bitmapをインスタンス化するコードでは、必ずOutOfMemory異常をキャプチャします.
Bitmap bitmap = null;
try {
    //    Bitmap
    bitmap = BitmapFactory.decodeFile(path);
} catch (OutOfMemoryError e) {
    //
}
if (bitmap == null) {
    //              Bitmap  
    return defaultBitmapMap;
}

ここではBitmapオブジェクトの初期化中に発生する可能性のあるOutOfMemory異常をキャプチャした.OutOfMemory異常が発生した場合、アプリケーションはクラッシュせず、デフォルトのBitmap図が得られます.
経験の共有:
    多くの開発者はコードの中でExceptionを直接キャプチャすることに慣れている.しかし、OutOfMemoryErrorにとって、これは捕獲できない.OutOfMemoryErrorはExceptionではなくErrorです.ここでは,コードを書き間違えてOutOfMemoryErrorがキャプチャされないように注意する.