2012-12-15 8 views
8

Buduję aplikację dla systemu Android, na której każda jednostka ma bitmapę, która reprezentuje jej ikonkę. Jednak każda jednostka może być duplikowana (na przykład mogą istnieć 3 kopie encji asdf).Słaba mahmap z słabymi odniesieniami do wartości?

Jednym ze sposobów jest załadowanie wszystkich duszków z góry, a następnie umieszczenie właściwego sprite'a w konstruktorach obiektów.

Jednak chcę dekodować bitmapy leniwie, aby konstruktorzy jednostek dekodują bitmapy. Jedyny problem polega na tym, że zduplikowane obiekty ładują tę samą bitmapę dwukrotnie, używając 2x pamięci (lub n razy, jeśli encja jest tworzona n razy).

Aby to naprawić, stworzyłem SingularBitmapFactory, który będzie przechowywać dekodowaną bitmapę w haszyszu i jeśli ta sama bitmapa zostanie ponownie zapytana, po prostu zwróci poprzednio mieszaną, zamiast budować nową. Problem polega jednak na tym, że fabryka posiada kopię wszystkich map bitowych, więc nigdy nie uda się zebrać śmieci.

Jaki jest najlepszy sposób na zmianę mapy izolacyjnej na wartość o słabo referencyjnych wartościach? Innymi słowy, chcę strukturę, w której wartości nie będą miały wartości GC, jeśli jakikolwiek inny obiekt będzie zawierał odniesienie do niej, ale tak długo, jak żaden inny obiekt go nie odwoła, może to być GC.

Odpowiedz

11

Prawie co powiedziałeś - spraw, aby bitmapa (strona obiektu mapy) była WeakReference zamiast bitmapy. Następnie musisz dodać dodatkową kontrolę, aby sprawdzić, czy referencja jest nadal ważna, zanim przekażesz ją do swoich jednostek. Oto krótki szkic ogólnej idei.

+0

niż ty! Jest dość prosty i BARDZO skuteczny w przypadku obsługi bitmapy. Używanie absolutnej ścieżki jako klucza i jest bardzo wygodne i pomogło pozbyć się przecieków. –

-3

Najlepszym sposobem jest użycie klasy WeakHashMap, która wykonuje całą pracę za Ciebie i nie wymaga żadnych zmian w kodzie. Tutaj jest naprawdę dobry tutorial: http://weblogs.java.net/blog/2006/05/04/understanding-weak-references To raczej staroświecki, ale nadal w porządku. Ważne jest, aby WeakHashMap zapisywał słabe odniesienie do klucza. Oznacza to, że nie można po prostu użyć stałej wartości ciągu jako klucza, ale zamiast tego użyć czegoś takiego jak liczba całkowita i zapisać ją w klasie stałych jako słabe odniesienie.

+1

Hmm, od opisu, WeakHashMap wydaje się słabym odniesieniem do klucza, nie do wartości. –

+0

To robi. Dzięki. Edytowałem odpowiedź. – SIGKILL

+1

to nie odpowiada na pytanie – siledh

7

Stare pytanie, ale musiałem to dzisiaj, i na podstawie odpowiedzi @ iagreen za Mam uogólnionej pomysł, może to jest przydatna dla kogoś ...

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)); 
    } 
} 

więc można po prostu zrobić na przykład

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

, a rysunki będą przechowywane pod numerem Weakreferences.

Metoda „containsValue” byłoby trudniejsze do wykonania, trzeba by iteracji i dereference wszystkich WeakRefs ...

+2

Wydaje się być całkiem OK: Myślę, że powinieneś zadbać o przestarzałe usuwanie kluczy. Po chwili wiele klawiszy sprawi, że wyszukiwanie będzie wolniejsze. (LoadFactor będzie wysoki, pochłonie dużo miejsca). jeśli nie usuniesz również klucza. Sugestia: usuń mDatabase z metody get w przypadku, gdy weakRef == null. Twoje zdrowie – kisp