Utrwalanie danych przy użyciu klasy Android Application

112

Pracuję nad dość złożoną aplikacją na Androida, która wymaga dość dużej ilości danych o aplikacji (powiedziałbym, że łącznie około 500KB - czy to dużo jak na urządzenie mobilne?). Z tego co wiem, każda zmiana orientacji w aplikacji (a dokładniej w działaniu) powoduje całkowite zniszczenie i odtworzenie działania. Z moich ustaleń wynika, że ​​klasa Application nie ma tego samego cyklu życia (tj. Jest zawsze tworzona dla wszystkich zamiarów i celów). Czy ma sens przechowywanie informacji o stanie wewnątrz klasy aplikacji, a następnie odwoływanie się do nich z działania, czy też generalnie nie jest to „akceptowalna” metoda ze względu na ograniczenia pamięci na urządzeniach mobilnych? Naprawdę doceniam każdą radę na ten temat. Dzięki!

Dave
źródło
8
Pamiętaj tylko, że dane w aplikacji mogą nadal zostać usunięte, jeśli aplikacja przejdzie w tło, więc nie jest to rozwiązanie dla utrwalonych danych, które zawsze chcesz mieć możliwość odzyskania. Służy tylko jako metoda, dzięki której nie trzeba tak często odtwarzać drogich obiektów.
Cheryl Simon
2
Mayra; Nie wydaje mi się, aby ta aplikacja była „zwykle” usuwana (chociaż, jak ktoś wskazuje w dalszej części tego wątku, „może” być). Prawdopodobnie zdecyduję się na jakiś rodzaj „hybrydowego” podejścia polegającego na używaniu aplikacji do przechowywania i ładowania danych, ale potem użyję atrybutu „android: orientacja” w działaniu w pliku manifestu, aby zastąpić normalne zachowanie zburzenie i odbudowanie działalności. Wszystko to oczywiście zakłada, że ​​aplikacja potrafi określić „kiedy” jest niszczona, aby dane mogły zostać utrwalone.
Dave

Odpowiedzi:

134

Nie sądzę, aby 500 kB było aż tak wielkim problemem.

To, co opisałeś, to dokładnie sposób, w jaki poradziłem sobie z problemem utraty danych w działaniu. Utworzyłem globalny singleton w klasie Application i mogłem uzyskać do niego dostęp z działań, z których korzystałem.

Możesz przekazywać dane w Global Singleton, jeśli ma być często używany.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Następnie nazwij to w dowolnej czynności przez:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

Omawiam to tutaj w moim poście na blogu , w sekcji „Global Singleton”.

Bryan Denny
źródło
1
Niestety, dany post na blogu nie jest już dostępny pod tym adresem.
mikebabcock
1
Poruszałem się po mojej witrynie. Dopóki to nie zostanie naprawione, można go znaleźć na archive.org tutaj: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny
1
Wiem, że to stary post, ale właśnie natknąłem się na problem, który może rozwiązać, jednak ta klasa musi być jakoś zadeklarowana w manifeście, nie? nie mogę przejść klasy, więc czuję, że właśnie tego mi brakuje ...
Ziv Kesten
1
@ZivKesten Co powiesz na dodanie atrybutu name = do tagu aplikacji w manifeście?
MikeC
@mgc dziękuję, minęło trochę czasu i tak to w końcu wypracowałem, również stworzyłem instancje tej klasy, gdziekolwiek potrzebowałem, dając jej getApplicationContext () z obsadą do tej klasy
Ziv Kesten
57

Ci, którzy liczą na Applicationinstancję, są w błędzie. Na początku może się wydawać, że Applicationistnieje tak długo, jak istnieje cały proces aplikacji, ale jest to błędne założenie.

System operacyjny może w razie potrzeby zabijać procesy. Wszystkie procesy są podzielone na 5 poziomów „kruchości” określonych w dok .

Na przykład, jeśli Twoja aplikacja działa w tle, ponieważ użytkownik odbiera połączenie przychodzące, to w zależności od stanu pamięci RAM system operacyjny może (lub nie) zabić proces (niszcząc Applicationinstancję w procesie) .

Myślę, że lepszym podejściem byłoby utrwalenie danych w pliku pamięci wewnętrznej, a następnie odczytanie go po wznowieniu działania.

AKTUALIZACJA:

Otrzymałem wiele negatywnych informacji zwrotnych, więc czas dodać wyjaśnienie. :) Cóż, początkowo naprawdę przyjąłem błędne założenie, że stan jest naprawdę ważny dla aplikacji. Jeśli jednak Twoja aplikacja jest w porządku, że czasami stan jest tracony (mogą to być niektóre obrazy, które zostaną ponownie odczytane / ponownie załadowane), to w pełni można zachować ją jako członka Application.

Vit Khudenko
źródło
14
Jeśli aplikacja zostanie zabita, to kogo to obchodzi, prawda? Aplikacja zniknęła. Jak rozumiem, Android odzyska procesy zawierające pamięć, takie jak Działania. Jeśli proces zawierający Aplikację zostanie zabity (jeśli Android to zrobi?), Jest to zasadniczo podobne do zabicia aplikacji. Użytkownik będzie musiał ponownie uruchomić aplikację i na tym etapie kogo to obchodzi? To nowa instancja aplikacji.
Andrew
14
To była dla nas nieprzyjemna niespodzianka w produkcji. Uwierz mi, że Android zabija procesy, zależy to tylko od stanu pamięci RAM i innych czynników opisanych w dokumentacji. To był dla nas koszmar, więc po prostu dzielę się swoim prawdziwym doświadczeniem. Cóż, nie mieliśmy tego na emulatorach, ale w prawdziwym świecie niektóre urządzenia są „przeładowane” aplikacjami, więc zabicie procesu w tle jest normalną sytuacją. Tak, jeśli użytkownik zdecyduje się przenieść aplikację na pierwszy plan - system operacyjny przywróci swój stos, w tym Applicationinstancję, jednak nie będzie można liczyć na statyczne dane, chyba że je utrwalisz.
Vit Khudenko
2
Myślę, że prawdopodobnie zastosuję podejście hybrydowe. Wiedziałem już o oczywistej sztuczce, aby zastąpić zmianę orientacji (która ma inne zalety). Ponieważ aplikacja jest grą, nie jestem pewien, czy utrwalanie danych między premierami jest wystarczająco „ważne”; chociaż prawdopodobnie nie byłoby to strasznie trudne, ponieważ większość danych można serializować (chociaż nie chciałbym serializować i odserializować między każdą zmianą orientacji). Zdecydowanie doceniam wkład. Nie powiedziałbym, że te, które zależą od instancji aplikacji, są „złe”. Wiele zależy od aplikacji :).
Dave
1
@Arhimed, zbyt uogólniasz swoją odpowiedź. I sugerując wąskie podejście oparte na twoim założeniu. Fałszywe założenie: dane przechowywane w zmiennych statycznych muszą być utrwalane w sesjach aplikacji. Może istnieć wiele przypadków użycia, w których dane są trywialne i nie muszą być natychmiast utrwalane.
Mandar Limaye,
2
Mam około 1 MB danych o skomplikowanej strukturze. Serializacja / deserializacja może kosztować mnie do 2-3 sekund, gdy urządzenie jest przeciążone pracą. Pomysł zapisywania / wczytywania między czynnościami kosztuje zbyt dużo czasu. Używam aplikacji jako magazynu. Oczywiście moja klasa danych przechowywana w instancji aplikacji ma sprawdzanie na każdej metodzie - czy dane są nadal żywe lub muszą zostać załadowane. Dlatego Dave musi: 1. zapewnić finalizację ładowania / zapisywania 2. przechowywać dane w aplikacji. 3. Logika potrójnego sprawdzenia dostępu do danych.
Kostadin
6

Jeśli chcesz uzyskać dostęp do „Global Singleton” poza działaniem i nie chcesz przepuszczać Contextwszystkich zaangażowanych obiektów w celu uzyskania singletona, możesz po prostu zdefiniować statyczny atrybut w swojej klasie aplikacji, który zawiera odniesienie do samo. Po prostu zainicjalizuj atrybut w onCreate()metodzie.

Na przykład:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Ponieważ podklasy Applicationrównież mogą uzyskiwać zasoby, można uzyskać do nich dostęp po zdefiniowaniu metody statycznej, która zwraca je, na przykład:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Ale zachowaj ostrożność podczas przekazywania odwołań do kontekstu, aby uniknąć wycieków pamięci .

Saxos
źródło
6
Zapomniałeś zauważyć, że aby utworzyć instancję klasy, musisz dodać atrybut android: name = ". ApplicationController" do znacznika aplikacji w swoim manifeście.
eggie5
W rzeczywistości nie musisz tego przedłużać Application. Aby to zrobić, możesz zadeklarować statyczną zmienną składową w dowolnej klasie .
David Wasser
2

Dave, jakie to dane? Jeśli są to dane ogólne, które dotyczą aplikacji jako całości (przykład: dane użytkownika), rozszerz klasę Application i zapisz ją w niej. Jeśli dane dotyczą działania, należy użyć programów obsługi onSaveInstanceState i onRestoreInstanceState, aby zachować dane podczas obracania ekranu.

Andrzej
źródło
Co się stanie, jeśli dane do przechowywania w paczce są naprawdę duże? Oto, co otrzymuję: android.os.TransactionTooLargeException: rozmiar paczki danych 838396 bajtów
Arjun Issar
1

W rzeczywistości możesz zastąpić funkcję orientacji, aby upewnić się, że Twoja aktywność nie zostanie zniszczona i odtworzona. Spójrz tutaj .

Grantland Chew
źródło
16
Możesz zrobić wiele rzeczy. To nie znaczy, że to dobre pomysły. To nie jest dobry pomysł.
Andrew
Testowanie poprzez zmianę orientacji ekranu to najłatwiejszy sposób na upewnienie się, że aplikacja działa zgodnie z założeniami Androida.
18446744073709551615
0

Możesz utworzyć klasę Application i zapisać wszystkie swoje dane w tych plikach do użytku w dowolnym miejscu aplikacji.

Ashish Jaiswal
źródło
0

Wiem, że jest to bardzo stare pytanie, ale użycie ViewModel z komponentów plecaka odrzutowego jest najlepszym sposobem na zachowanie danych między rotacją aktywności.

Klasa ViewModel jest przeznaczona do przechowywania danych związanych z interfejsem użytkownika i zarządzania nimi w sposób uwzględniający cykl życia. Klasa ViewModel umożliwia przetrwanie danych po zmianach konfiguracji, takich jak obracanie ekranu.

Dharmendra
źródło