Autor Wątek: Android zasoby aktywności.  (Przeczytany 2385 razy)

Offline kokos22

  • Użytkownik

# Wrzesień 12, 2013, 14:23:33
Nie wiem czy dobrze trafiłem z działem, ewentualnie proszę o przeniesienie.
Co do mojego problemu.  Napisałem system zarządzania zasobami, został on umieszczony w pierwszej podstawowej aktywności. Jednak z tej aktywności uruchamiana będzie kolejna, czy dobrym pomysłem jest przekazanie jej wskaźnika do zasobów pierwszej aktywności? Czy po prostu stworzyć drugi resourceManager w drugiej aktywności?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline shoter

  • Użytkownik

# Wrzesień 12, 2013, 15:39:51
Poczytaj o dziedziczeniu Application i tam to umieść. Ma podobne metody co aktywność które są wywoływane podczas odpowiednich zdarzeń związanych z aplikacją.

Offline Xion

  • Redaktor
    • xion.log

  • +3
# Wrzesień 12, 2013, 19:22:09
W apce androidowej możesz normalnie używać singletonów i mieć coś w tym stylu:
public class ResourceManager {
    private static ResourceManager sInstance = null;

    public static ResourceManager getInstance() {
        if (sInstance == null) {
            sInstance = new ResourceManager();
        }
        return sInstance;
    }

    // ... reszta kodu ...
}
Żeby jednak uniknąć całego tego boilerplate'u i długich wywołań ResourceManager.getInstance(), to proponuję zainteresować się projektem Android Annotations, który pozwala zredukować to mniej więcej czegoś takiego:
@EBean(scope = Scope.SINGLETON)
public class ResourceManager {
    @App android.app.Application mApplication;

    // ...reszta kodu...
}
gdzie użycie to po prostu:
@EActivity
public class MyActivity {
    @Bean ResourceManager mResourceManager;

    private void someMethod() {
        mResourceManager.doSomeStuff();
    }
}

Offline kokos22

  • Użytkownik

# Wrzesień 12, 2013, 21:39:18
No tak ale czy moje zasoby będą bezpieczne podczas działania drugiej aktywności i np. braku pamięci ?

Offline Xion

  • Redaktor
    • xion.log

# Wrzesień 13, 2013, 00:05:03
System w pierwszej kolejności ubije activities pod spodem aktualnej. Jeśli ubija też aktualną, to zużywasz za dużo pamięci :)

Offline deadeye

  • Użytkownik

# Wrzesień 13, 2013, 02:27:33
No tak ale czy moje zasoby będą bezpieczne podczas działania drugiej aktywności i np. braku pamięci ?
Statyczne dane (nawet te wewnątrz klas Activity) nie podlegają pod cykl życia aktywności, tylko procesu. Gdy jakakolwiek twoja activity jest na wierzchu, wartości wszystkich staticów zostaną zachowane, i system ani menadżer pamięci ich nigdy nie zwolni (co może być przyczyną leaków i problemów z pamięcią). Ale gdy user zminiamalizuje twoją apke, i zacznie korzystać z kolejnej, to system może skillować cały proces, w efekcie kasując wszystkie dane ze staticów. Gdy później user wróci do twojej aplikacji, to system odtworzy proces i activity które były ostatnio włączone w twojej apce, ale NIE przywróci staticów - więc nie będziesz miał dostępu do danych. Jeśli już używasz static to jedyne rozwiązanie to ręcznie wykrywać taką sytuacje, i albo restartować apkę aby cała inicjalizacja przegiegła od początku, albo przywracać dane statyczne z pliku (gdzie muszą być zapisywane na bieżąco).

Dlatego opcja korzystania z intentów i bundle, chociaż bardzo upierdliwa, jest lepsza od static (może poza przekazywaniem dużych binarnych danych, jak obrazki), ponieważ system wie że informacje przekazywane w ten sposób muszą być przywrócone przy odtwarzaniu procesu, i przywróci je automatycznie, przekazując w onCreate przy odtwarzaniu aktywności.

System w pierwszej kolejności ubije activities pod spodem aktualnej. Jeśli ubija też aktualną, to zużywasz za dużo pamięci :)
System nigdy nie killuje front activity, bo ma najwyższy priorytet - skilluje wszystkie inne activities i services, a jeśli dalej braknie pamięci to twój kod próbująć coś zaalokować zcrashuje się przez OOM.
« Ostatnia zmiana: Wrzesień 13, 2013, 02:34:12 wysłana przez deadeye »

Offline .Dexter.

  • Użytkownik

# Wrzesień 13, 2013, 09:30:57
Ja tylko pokażę podobno najlepszą implementację singletona w Javie:

public enum ResourceManager {
    INSTANCE;
    private int someField;

    public static int getSomeField() {
        return INSTANCE.someField;
    }
}

Cytuj
This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.
- Joshua Bloch "Effective Java 2nd Edition"

Offline Xion

  • Redaktor
    • xion.log

  • +1
# Wrzesień 13, 2013, 10:58:56
Cytuj
Ale gdy user zminiamalizuje twoją apke, i zacznie korzystać z kolejnej, to system może skillować cały proces, w efekcie kasując wszystkie dane ze staticów. Gdy później user wróci do twojej aplikacji, to system odtworzy proces i activity które były ostatnio włączone w twojej apce, ale NIE przywróci staticów - więc nie będziesz miał dostępu do danych.
Zakładam, że chodzi ci o to, iż system nie robi dumpa pamięci procesu żeby go potem z niego przywrócić. Ano nie robi, bo nie miałoby to sensu. Dane, które chcesz zachować, zapisujesz w onSaveInstanceState(), nie wspominając już o wszelakich metodach permanentnego ich zapisu, jak SharedPreferences czy bazy SQLite.

Cytuj
Jeśli już używasz static to jedyne rozwiązanie to ręcznie wykrywać taką sytuacje, i albo restartować apkę aby cała inicjalizacja przegiegła od początku, (...)
Piszesz tak, jakby to był jakiś niewiarygodnie skomplikowany proces. W rzeczywistości załatwia to dokładnie ten prosty `if` z mojej implementacji singletona, albo wręcz sama JVMka (w wersji z enumem). To co proponujesz zamiast tego:
Cytuj
Dlatego opcja korzystania z intentów i bundle, chociaż bardzo upierdliwa, jest lepsza od static (może poza przekazywaniem dużych binarnych danych, jak obrazki), ponieważ system wie że informacje przekazywane w ten sposób muszą być przywrócone przy odtwarzaniu procesu, i przywróci je automatycznie, przekazując w onCreate przy odtwarzaniu aktywności.
jest nie tylko bardziej skomplikowane, ale i potwornie upierdliwe dla systemu, który musi przepchać twoje dane przez kilka procesów (de)serializacji. Są dane które na to zasługują, lecz niemal zawsze są one bardzo małe (draft maila/posta, numer levelu / stan gry, etc.). Assety? Lolwut?

Cytuj
Ja tylko pokażę podobno najlepszą implementację singletona w Javie:
Zauważ, że nie jest ona ekwiwalentem tej podanej przeze mnie. Ponieważ tworzenie obiektu nie jest jawne (robi to JVM), zrobienie tego "leniwie" i np. przerzucenie do innego wątku ociera się trochę o niepotrzebne czarowanie (na pewno mniej oczywiste niż zwykły `if`). A w przypadku czegoś takiego jak ResourceManager, chciałbyś robić jedno i drugie.

// EDIT: Zapomniałem jeszcze o najważniejszym mankamencie singletona opartego na enumie w kontekście Androida. A właściwie w Context'cie, bo żeby zrobić cokolwiek interesującego, potrzeba przecież zawsze obiektu android.app.Context, do którego nie będziesz miał dostępu w momencie, gdy instancja enuma jest tworzona.
Oczywiście oznacza to też, że w wersji z polem statycznym odwołanie będzie wyglądało np. a tak:
ResourceManager.getInstance(this)
ResourceManager.getInstance(getActivity())
ResourceManager.getInstance(getContext())
ResourceManager.getInstance(mContext)
co jest kolejnym argumentem na rzecz korzystania z depedency injection.
« Ostatnia zmiana: Wrzesień 13, 2013, 16:29:33 wysłana przez Xion »