Android Cómo reciclar el mapa de bits correctamente cuando se utiliza RecyclerView?

Como google's dijo que debemos llamar manualmente Bitmap.recycle () cuando el mapa de bits no utilizar debajo de Android 3.0 porque la memoria se mantienen en el montón nativo.

Así que podríamos tener un recuento de referencia para un mapa de bits y comprobar si es necesario reciclar el mapa de bits en ImageView's onDetachedFromWindow () cuando se utiliza ListView. Esta es la solución del proyecto de demostración de Google Bitmapfun (ImageFetcher).

Pero cuando se utiliza RecyclerView, la conversión a menudo se separa y se adjunta. OnDetachedFromWindow () tal vez reciclar el mapa de bits, así que cuando se adjunta a los padres de nuevo el mapa de bits se ha reciclado.

¿Cómo lidiar con este problema? ¿Cuál es la forma correcta de reciclar bitmap debajo de Android 3.0 cuando se usa RecyclerView?

Esta es la demostración de Googls BitmapFun (ImageFetcher) de la solucación – ampliar ImageView:

@Override protected void onDetachedFromWindow() { // This has been detached from Window, so clear the drawable setImageDrawable(null); super.onDetachedFromWindow(); } @Override public void setImageDrawable(Drawable drawable) { // Keep hold of previous Drawable final Drawable previousDrawable = getDrawable(); // Call super to set new Drawable super.setImageDrawable(drawable); // Notify new Drawable that it is being displayed notifyDrawable(drawable, true); // Notify old Drawable so it is no longer being displayed notifyDrawable(previousDrawable, false); } private static void notifyDrawable(Drawable drawable, final boolean isDisplayed) { if (drawable instanceof RecyclingBitmapDrawable) { // The drawable is a CountingBitmapDrawable, so notify it ((RecyclingBitmapDrawable) drawable).setIsDisplayed(isDisplayed); } else if (drawable instanceof LayerDrawable) { // The drawable is a LayerDrawable, so recurse on each layer LayerDrawable layerDrawable = (LayerDrawable) drawable; for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) { notifyDrawable(layerDrawable.getDrawable(i), isDisplayed); } } } 

Y también en LruCache cuando se quita del caché de memoria:

  @Override protected void entryRemoved(boolean evicted, String key, BitmapDrawable oldValue, BitmapDrawable newValue) { if (RecyclingBitmapDrawable.class.isInstance(oldValue)) { // The removed entry is a recycling drawable, so notify it // that it has been removed from the memory cache ((RecyclingBitmapDrawable) oldValue).setIsCached(false); 

El RecyclingBitmapDrawable es:

 public class RecyclingBitmapDrawable extends BitmapDrawable { static final String TAG = "CountingBitmapDrawable"; private int mCacheRefCount = 0; private int mDisplayRefCount = 0; private boolean mHasBeenDisplayed; public RecyclingBitmapDrawable(Resources res, Bitmap bitmap) { super(res, bitmap); } /** * Notify the drawable that the displayed state has changed. Internally a * count is kept so that the drawable knows when it is no longer being * displayed. * * @param isDisplayed - Whether the drawable is being displayed or not */ public void setIsDisplayed(boolean isDisplayed) { //BEGIN_INCLUDE(set_is_displayed) synchronized (this) { if (isDisplayed) { mDisplayRefCount++; mHasBeenDisplayed = true; } else { mDisplayRefCount--; } } // Check to see if recycle() can be called checkState(); //END_INCLUDE(set_is_displayed) } /** * Notify the drawable that the cache state has changed. Internally a count * is kept so that the drawable knows when it is no longer being cached. * * @param isCached - Whether the drawable is being cached or not */ public void setIsCached(boolean isCached) { //BEGIN_INCLUDE(set_is_cached) synchronized (this) { if (isCached) { mCacheRefCount++; } else { mCacheRefCount--; } } // Check to see if recycle() can be called checkState(); //END_INCLUDE(set_is_cached) } private synchronized void checkState() { //BEGIN_INCLUDE(check_state) // If the drawable cache and display ref counts = 0, and this drawable // has been displayed, then recycle if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed && hasValidBitmap()) { if (BuildConfig.DEBUG) { Log.d(TAG, "No longer being used or cached so recycling. " + toString()); } getBitmap().recycle(); } //END_INCLUDE(check_state) } private synchronized boolean hasValidBitmap() { Bitmap bitmap = getBitmap(); return bitmap != null && !bitmap.isRecycled(); } 

}

El punto importante está en OnDetachedFromWindow de ImageView: setImageDrawable (null) significa claro dibujable, puede hacer que el recuento actual de drawble = 0 y lo recicle! Esta solución funciona bien cuando se utiliza ListView porque onDetachedFromWindow sólo ocurre cuando se destruye la actividad raíz de ListView.

Pero el uso de Recyclering es diferente, este Reusing ConvertView's Mechanism no es el mismo que ListView. ImageView tal vez a menudo separado y no es el momento correcto para reciclar Bitmap!

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.