2012-12-15 19 views
8

Sto costruendo un'app per Android in cui ogni entità ha una bitmap che rappresenta il suo sprite. Tuttavia, ogni entità può essere duplicata (potrebbero esserci 3 copie di entità asdf per esempio).Debole hashmap con riferimenti deboli ai valori?

Un approccio consiste nel caricare tutti gli sprite in anticipo e quindi inserire lo sprite corretto nei costruttori delle entità.

Tuttavia, voglio decodificare le bitmap pigramente, in modo che i costruttori delle entità decodificheranno le bitmap. L'unico problema è che le entità duplicate caricheranno la stessa bitmap due volte, usando 2x la memoria (o n volte se l'entità viene creata n volte).

Per risolvere questo problema, ho creato un SingularBitmapFactory che memorizzerà un bitmap decodificato in un hash e, se viene richiesto di nuovo lo stesso bitmap, verrà semplicemente restituito quello precedente e non ne verrà creato uno nuovo. Il problema, tuttavia, è che la fabbrica contiene una copia di tutte le bitmap e quindi non verrà mai raccolta la garbage collection.

Qual è il modo migliore per passare l'hashmap a uno con valori debolmente referenziati? In altre parole, voglio una struttura in cui i valori non saranno GC se qualsiasi altro oggetto contiene un riferimento ad esso, ma fino a quando nessun altro oggetto lo fa riferimento, allora può essere GC'd.

risposta

11

Praticamente quello che hai detto - rendere Bitmap (lato oggetto della mappa) un WeakReference invece di un Bitmap. Quindi devi aggiungere un controllo extra per vedere se il riferimento è ancora valido prima di restituirlo alle tue entità. Ecco un rapido schizzo dell'idea generale.

public class SingularBitmapFactory { 
    private HashMap <String, WeakReference<Bitmap>> cache = new HashMap<String, WeakReference<Bitmap>>(); 

    public Bitmap getBitmap(String key) { 
     Bitmap image = null; 
     WeakReference<Bitmap> ref = cache.get(key); 
     if(ref != null) { 
      image = ref.get(); 
     } 
     if(image == null) { 
      // Load image here ... 
      cache.put(key, new WeakReference<Bitmap>(image)); 
     } 
     return image; 
    } 
} 
+0

di te! È piuttosto semplice e MOLTO efficace in caso di gestione di bitmap. Solo utilizzando il percorso assoluto come chiave ed è molto conveniente e ha contribuito a eliminare le perdite –

-3

Il modo migliore è utilizzare la classe WeakHashMap che fa tutto il lavoro per voi e non richiede alcuna modifica nel codice. C'è un buon tutorial qui: http://weblogs.java.net/blog/2006/05/04/understanding-weak-references È piuttosto vecchio ma va bene. È importante che WeakHashMap memorizzi un riferimento debole alla chiave. Ciò significa che non puoi semplicemente usare un valore di stringa costante come chiave, ma invece usare qualcosa come un intero e memorizzarlo in una classe di costanti come riferimento debole.

+1

Hmm, dalla descrizione, WeakHashMap sembra riferimenti deboli alla chiave non al valore. –

+0

Lo fa. Grazie. Ho modificato la risposta. – SIGKILL

+1

questo non risponde alla domanda – siledh

7

vecchia questione, ma avevo bisogno di questo oggi, e in base alla risposta di @ iagreen ho generalizzato l'idea, forse è utile a qualcuno ...

public static class WeakValueHashMap<K,V> { 
    private HashMap<K,WeakReference<V>> mDatabase=new HashMap<K, WeakReference<V>>(); 
    public V get(K key) { 
     WeakReference<V> weakRef=mDatabase.get(key); 
     if (weakRef==null) return null; 
     V result=weakRef.get(); 
     if (result==null) { 
      // edge case where the key exists but the object has been garbage collected 
      // we remove the key from the table, because tables are slower the more 
      // keys they have (@kisp's comment) 
      mDatabase.remove(key); 
     } 
     return result; 
    } 
    public void put(K key, V value) { 
     mDatabase.put(key, new WeakReference<V>(value)); 
    } 
} 

Così si può fare solo per esempio

private WeakValueHashMap<String,Drawable> mTextDrawables=new WeakValueHashMap<String,Drawable>(); 

ei drawable viene memorizzato con Weakreferences.

Il metodo "containsValue" sarebbe più complicato da implementare, dovreste iterare e dereferenziare tutte le WeakRefs ...

+2

Sembra essere abbastanza OK: penso che si dovrebbe prendere cura della rimozione delle chiavi obsolete. Dopo un po 'molte chiavi renderanno la ricerca più lenta. (Il load factor sarà alto, consumerà molto spazio). se non si rimuove anche la chiave. Suggerimento: creare un mDatabase remove nel metodo get nel caso weakRef == null. Saluti – kisp