私たちはそれぞれURLによる画像の読み込みに直面していると思います。 この問題を解決する最も簡単な方法は、既製のサードパーティライブラリを使用することです。 原則として、そのような既製のソリューションの1つは、ユニバーサルイメージローダー(UIL)、ピカソです。 開発者にこのライブラリまたはそのライブラリを選択した理由を尋ねると、原則として異なる答えが得られます。 たとえば、「Picasso / UILにはメモリリークの問題はありません」、「Squareは正しいことだけを実行します」、または単に「はい、UILを使用すると動作します-そして良い」。
だから、私は疑問に思っていました:これらの2つのライブラリのうち、メモリを最適に使用するのはどれですか UILを使用していますが、古いデバイスのOutOfMemoryに問題があります。 おそらくピカソが治療法でしょうか?
そこで、このベンチマークのアイデアが現れました。
テストの目的:デバイスのメモリを最小限使用するライブラリ(UILまたはPicasso) を決定する。
テストケース:
-小さな画像のダウンロード(240x240)
-大きな画像をダウンロード(任意のサイズで400ピクセル以上)
-大きな画像をダウンロードし、そのサイズをImageViewの寸法に変換します
-小さな画像をダウンロードして、丸い画像として表示します
-大きな画像をダウンロードしてRGB565構成で表示する
テスト実行テクニック:
リストとして、幅2列のGridViewを使用します。 アダプターは、テストケースごとに個別に構成されます。 アダプタに事前に準備されたURLのリストを提供するため、同じテスト条件が作成されます。
1秒の期間で、リストは1つのパスを自動的に1つ下に移動してから、4つのイメージの増分で上に移動します。 各ステップで、アプリケーションが使用するメモリが測定されます。
各テストケースについて、使用済みメモリを3段階で測定します。
-最初の実行-クリーンなアプリケーションキャッシュを使用。
-2回目の起動:最初のパスの後、アプリケーションを閉じません。
-3回目の起動-キャッシュを消去せずにアプリケーションを再度開いた後。
テストケースの最後に、キャッシュサイズをさらに書き留めました。これは、古いデバイスにとっても重要です。
ベンチマークのソースはここにあります
github.com/artemmanaenko/ImageLoadersTest プロジェクトはGradleの下でコンパイルされます。
したがって、以下は各テストケースの結果です。 Y軸-アプリケーションが使用するメモリ(MB単位)。 X軸-テストケースの時間。
小さな画像をダウンロードする
キャッシュサイズ:ピカソ= 1.39 Mb、UIL = 1.17 Mb
大きな画像をダウンロードする
キャッシュサイズ:ピカソ= 3.67 Mb、UIL = 5.44 Mb
ImageViewサイズに変換して大きな画像をダウンロードする
キャッシュサイズ:ピカソ= 3.67 Mb、UIL = 5.44 Mb
小さな画像をダウンロードして、丸い画像にトリミングします
キャッシュサイズ:ピカソ= 1.39 Mb、UIL = 1.17 Mb
大きな画像をダウンロードしてRGB565構成で表示する
大きな写真を使った実験の結果に感銘を受け、UILを構成する価値があると判断しました。 キャッシュにキャッシュを大量にロードしないように、UILのRAMでキャッシュを無効にしようとしました。 そして、オプションとして、画像のキャッシュ可能なサイズを設定します-画面の半分以下です。
実験に基づいて、私は次の結論を出しました。
- リストが小さな画像(ImageViewのサイズと同等)で機能する場合-ライブラリの選択は重要ではありません。 Picassoは、ディスク上にわずかに大きなキャッシュを作成しますが、使用するRAMはほぼ同じサイズです。
- ピカソは、大きな画像を操作する場合、メモリ管理で驚くべき結果を示しました。 UILは元の画像をメモリに保存しているようです。 Picassoは、既に変換された画像サイズを保存します。 したがって、ピカソのディスク上のキャッシュははるかに少なくなります。
- UILが追加構成されている場合、Picassoと同じ効率で動作できます。 たとえば、メモリ内のキャッシュのサイズを制限します。 または、いずれかのテストのように、キャッシュされた写真のサイズを手動で制限します。 2番目の方法は、ImageLoaderのグローバル構成を設定するため、使用に適さない場合があります。
- 丸いアバターを操作するのは、ピカソを介して「安く」することです。 しかし、ここでも、元のビットマップで手動でrecycle()を呼び出したためです。 オーバーライドされたBitmapDisplayerを設定することにより、UILでも同じことができます。
- Picassoは非常に使いやすく、すぐに使用できるメモリを効率的に使用できます。 ライブラリの初期化とロードは次のようになります。
ピカソpublic class PicassoSquareFitAdapter extends BaseBenchmarkAdapter { public PicassoSquareFitAdapter(Context context, IUrlListContainer urlListContainer) { super(context, urlListContainer); } @Override protected void loadImage(ImageView imageView, String url) { Picasso.with(context).load(url).fit().into(imageView); } }
ウイルpublic class UILSquareFitAdapter extends BaseBenchmarkAdapter { private DisplayImageOptions options; public UILSquareFitAdapter(Context context, IUrlListContainer urlListContainer) { super(context, urlListContainer); ImageLoaderConfiguration config = ImageLoaderConfiguration.createDefault(context); ImageLoader.getInstance().init(config); options = new DisplayImageOptions.Builder() .imageScaleType(ImageScaleType.EXACTLY) .resetViewBeforeLoading(true) .cacheInMemory(true) .cacheOnDisc(true) .build(); } @Override protected void loadImage(ImageView imageView, String url) { ImageLoader.getInstance().displayImage(url, imageView, options); } }
- ピカソにはマイナス面もあります。画像変換とRGB565へのキャストは、自己記述型のクラスで行う必要があります。
ラウンド変換public class RoundTransformation implements Transformation { @Override public Bitmap transform(Bitmap source) { int size = Math.min(source.getWidth(), source.getHeight()); int x = (source.getWidth() - size) / 2; int y = (source.getHeight() - size) / 2; Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); if (squaredBitmap != source) { source.recycle(); } Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig()); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); paint.setShader(shader); paint.setAntiAlias(true); float radius = size / 2f; canvas.drawCircle(radius, radius, radius, paint); squaredBitmap.recycle(); return bitmap; } @Override public String key() { return "circle"; } }
Config565Transformationpublic class Config565Transformation implements Transformation { @Override public Bitmap transform(Bitmap source) { Bitmap resultBitmap = Bitmap.createBitmap( source.getWidth(), source.getHeight(), Bitmap.Config.RGB_565 ); Canvas canvas = new Canvas(resultBitmap); Paint paint = new Paint(); paint.setFilterBitmap(true); canvas.drawBitmap(source, 0, 0, paint); source.recycle(); return resultBitmap; } @Override public String key() { return "Config565Transformation"; } }
私自身は、プロジェクトをピカソに移す必要があると結論付けました。 私の場合、これはメモリオーバーランの問題を解決します。 この投稿があなたにも役立つことを願っています!