Mam jedno działanie, które jest głównym działaniem używanym w całej aplikacji i ma wiele zmiennych. Mam dwie inne aktywności, które chciałbym móc wykorzystać dane z pierwszej aktywności. Teraz wiem, że mogę zrobić coś takiego:
GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();
Jednak chcę udostępnić wiele zmiennych, a niektóre mogą być dość duże, więc nie chcę tworzyć ich kopii jak wyżej.
Czy istnieje sposób na bezpośrednie uzyskanie i zmianę zmiennych bez użycia metod get and set? Pamiętam, jak czytałem artykuł na stronie deweloperów Google, który powiedział, że nie jest to zalecane ze względu na wydajność na Androidzie.
Odpowiedzi:
Oto zestawienie najczęstszych sposobów osiągnięcia tego celu :
WeakReferences
TL; DR : istnieją dwa sposoby udostępniania danych: przekazywanie danych do dodatków intencji lub zapisywanie ich gdzie indziej. Jeśli dane są prymitywne, ciągi lub obiekty zdefiniowane przez użytkownika: wyślij je jako część zamierzonych dodatków (obiekty zdefiniowane przez użytkownika muszą zostać zaimplementowane
Parcelable
). Jeśli przekazujesz złożone obiekty, zapisz instancję w singletonie w innym miejscu i uzyskaj do nich dostęp z uruchomionej aktywności.Kilka przykładów tego, jak i dlaczego wdrożyć każde podejście:
Wysyłaj dane wewnątrz intencji
W sprawie drugiej aktywności:
Użyj tej metody, jeśli przekazujesz prymitywne dane lub ciągi . Możesz także przekazywać obiekty, które implementują
Serializable
.Choć kuszące, powinieneś pomyśleć dwa razy przed użyciem
Serializable
: jest podatne na błędy i strasznie powolne. Więc ogólnie: trzymaj się z daleka,Serializable
jeśli to możliwe. Jeśli chcesz przekazać złożone obiekty zdefiniowane przez użytkownika, spójrz naParcelable
interfejs . Jest trudniejszy do wdrożenia, ale w porównaniu do niego ma znaczny wzrost prędkościSerializable
.Udostępniaj dane bez utrwalania się na dysku
Możliwe jest współdzielenie danych między działaniami poprzez zapisanie ich w pamięci, biorąc pod uwagę, że w większości przypadków oba działania przebiegają w tym samym procesie.
Uwaga: czasami, gdy użytkownik opuści Twoją aktywność (bez wychodzenia z niej), Android może zdecydować o zabiciu Twojej aplikacji. W takim scenariuszu napotkałem przypadki, w których Android próbuje uruchomić ostatnią aktywność, wykorzystując zamiar podany przed śmiercią aplikacji. W takich przypadkach dane przechowywane w singletonie (twoje lub
Application
) znikną i mogą się zdarzyć złe rzeczy. Aby uniknąć takich przypadków, należy utrwalić obiekty na dysku lub sprawdzić dane przed ich użyciem, aby upewnić się, że są prawidłowe.Użyj klasy singleton
Poproś klasę, aby przechowała dane:
Z rozpoczętej działalności:
Użyj singletonu aplikacji
Singleton aplikacji to instancja
android.app.Application
tworzona podczas uruchamiania aplikacji. Możesz podać niestandardowy, rozszerzającApplication
:Przed rozpoczęciem działania:
Następnie z rozpoczętej działalności:
Pola statyczne
Pomysł jest zasadniczo taki sam jak singleton, ale w tym przypadku zapewniasz statyczny dostęp do danych:
Z rozpoczętej działalności:
HashMap of
WeakReferences
Ten sam pomysł, ale zezwalający śmieciarzowi na usuwanie niepowiązanych obiektów (np. Gdy użytkownik zakończy działanie):
Przed rozpoczęciem działania:
Z rozpoczętej działalności:
Możliwe, że nie musisz podawać identyfikatora obiektu przy użyciu dodatków intencji. Wszystko zależy od konkretnego problemu.
Utrwalaj obiekty na dysku
Chodzi o to, aby zapisać dane na dysku przed uruchomieniem innej czynności.
Zalety: możesz uruchomić działanie z innych miejsc, a jeśli dane są już utrwalone, powinno działać dobrze.
Wady: uciążliwe i zajmuje więcej czasu. Wymaga więcej kodu, a tym samym większej szansy na wprowadzenie błędów. Będzie też znacznie wolniej.
Niektóre sposoby utrwalania obiektów obejmują:
źródło
setResult
metody. Ponadto w takim przypadku działanie drugorzędne należy wywołać za pomocąstartActivityForResult
metody.Activity
całe ionCreate()
sprawdzając każde pole statyczne singletonu, które wypełniasz podczas uruchamiania aplikacji. Jeśli to pole jest puste, wróć do działania początkowego, używając przyciskuFLAG_ACTIVITY_CLEAR_TASK
lub,BroadcastReceiver
aby zabić inne działania.Czego możesz użyć:
To, co wybierzesz, zależy od twoich potrzeb. Prawdopodobnie skorzystasz z więcej niż jednego sposobu, gdy masz „dużo”
źródło
MAIN
. Po śmierci procesu wznawiasz wszystkie czynności, które były ostatnio otwarte, które mogą być szczegółowymi stronami gdzieś głęboko w aplikacji.Rób to, co nakazuje ci Google! tutaj: http://developer.android.com/resources/faq/framework.html#3
źródło
To nie tworzy kopii (szczególnie w przypadku String , ale nawet obiekty przechodzą przez wartość referencji, a nie sam obiekt, i podobne metody gettera są w użyciu - prawdopodobnie lepiej niż w inny sposób, ponieważ są wspólne i dobrze zrozumiane). Starsze „mity dotyczące wydajności”, takie jak nieużywanie programów pobierających i ustawiających, nadal mają pewną wartość, ale zostały również zaktualizowane w dokumentach .
Ale jeśli nie chcesz tego robić, możesz również ustawić zmienne jako publiczne lub chronione ustawić GlobalState i uzyskać do nich bezpośredni dostęp. I można utworzyć statyczny singleton, ponieważ obiekt aplikacji JavaDoc wskazuje :
Za pomocą danych zamiaru , jak zauważają inne odpowiedzi tutaj, to inny sposób przekazywania danych, ale zwykle jest używany do mniejszych danych i prostych typów. Możesz przekazywać większe / bardziej złożone dane, ale jest to bardziej zaangażowane niż tylko użycie pojedynczego statycznego pojedynczego elementu. Application jest nadal moim ulubionym miejscem do udostępniania większych / bardziej złożonych nietrwałych danych między komponentami aplikacji na Androida (ponieważ ma dobrze zdefiniowany cykl życia w aplikacji na Androida).
Ponadto, jak zauważyli inni, jeśli dane stają się bardzo złożone i muszą być trwałe , możesz użyć SQLite lub systemu plików.
źródło
Możesz rozszerzyć klasę aplikacji i tag na dowolne obiekty, które tam chcesz, są one następnie dostępne w dowolnym miejscu w aplikacji
źródło
Istnieje nowy i lepszy sposób udostępniania danych między działaniami, a jest nim LiveData . Zwróć uwagę w szczególności na ten cytat ze strony programisty Androida:
Konsekwencje tego są ogromne - wszelkie dane modelu mogą być współużytkowane we wspólnej klasie singletonów wewnątrz
LiveData
opakowania. Może być wstrzykiwany z działań do odpowiednichViewModel
dla celów testowalności. Nie musisz się już martwić słabymi referencjami, aby zapobiec wyciekom pamięci.źródło
Korzystanie z mapy skrótowej podejścia do słabych odniesień, opisanej powyżej oraz w http://developer.android.com/guide/faq/framework.htmlProblematyczne wydaje mi się . W jaki sposób odzyskuje się całe wpisy, a nie tylko wartość mapy? W jakim zakresie go przydzielasz? Ponieważ struktura kontroluje cykl życia działania, posiadanie jednego z uczestniczących działań może ryzykować błędy w czasie wykonywania, gdy właściciel zostanie zniszczony przed swoimi klientami. Jeśli aplikacja jest jej właścicielem, niektóre działania muszą jawnie usunąć wpis, aby uniknąć zatrzymania hashapy względem wpisów z ważnym kluczem i potencjalnie zniekształconym zbiorem słabych referencji. Co ponadto powinien zrobić klient, gdy wartość zwrócona dla klucza jest pusta?
Wydaje mi się, że lepszym wyborem jest WeakHashMap będący własnością aplikacji lub w ramach singletonu. Dostęp do wartości na mapie jest uzyskiwany za pomocą obiektu klucza, a gdy nie istnieją silne odniesienia do klucza (tzn. Wszystkie działania są wykonywane za pomocą klucza i tego, co jest mapowane), GC może odzyskać wpis na mapie.
źródło
Istnieją różne sposoby udostępniania danych między działaniami
1: Przekazywanie danych między działaniami przy użyciu zamiaru
2: Używając słowa kluczowego static, zdefiniuj zmienną jako publiczną statyczną i użyj dowolnego miejsca w projekcie
użyj w dowolnym miejscu w projekcie, używając classname.variableName;
3: Korzystanie z bazy danych
ale jest to nieco długi proces, musisz użyć zapytania do wstawienia danych i iterować dane za pomocą kursora, gdy zajdzie taka potrzeba. Ale nie ma szansy na utratę danych bez czyszczenia pamięci podręcznej.
4: Korzystanie ze wspólnych preferencji
znacznie łatwiejsze niż baza danych. ale istnieją pewne ograniczenia, których nie można zapisać ArrayList, List i obiektów klienta.
5: Utwórz narzędzie ustawiające getter w klasie Aplication i uzyskaj dostęp do dowolnego miejsca w projekcie.
tutaj ustaw i czerp z zajęć
źródło
Mam kilka pomysłów, ale nie wiem, czy są one tym, czego szukasz.
Możesz skorzystać z usługi, która przechowuje wszystkie dane, a następnie po prostu powiązać swoje działania z usługą w celu odzyskania danych.
Lub spakuj swoje dane do postaci szeregowej lub paczkowej i dołącz je do pakietu i przekaż pakiet między działaniami.
Ten może wcale nie być tym, czego szukasz, ale możesz także spróbować użyć wspólnych preferencji lub preferencji w ogóle.
Tak czy inaczej, daj mi znać, co zdecydujesz.
źródło
Zakładając, że wywołujesz działanie dwa z działania jeden za pomocą zamiaru.
Możesz przekazać dane za pomocą intent.putExtra (),
Weź to w celach informacyjnych. Wysyłanie tablic za pomocą Intent.putExtra
Mam nadzieję, że tego właśnie chcesz.
źródło
Jeśli zamierzasz wywoływać inne działania z bieżącej działalności, powinieneś użyć intencji . Możesz skupić się mniej na utrwalaniu danych niż na udostępnianiu ich w razie potrzeby.
Jeśli jednak naprawdę chcesz zachować te wartości, możesz utrwalić je w jakimś strukturalnym pliku tekstowym lub bazie danych w pamięci lokalnej. Plik właściwości, plik XML lub plik JSON może przechowywać dane i być łatwo analizowany podczas tworzenia działania. Nie zapomnij również, że masz SQLite na wszystkich urządzeniach z Androidem, więc możesz przechowywać je w tabeli bazy danych. Możesz także użyć mapy do przechowywania par klucz-wartość i serializacji mapy do pamięci lokalnej, ale może to być zbyt skomplikowane, aby było przydatne w przypadku prostych struktur danych.
źródło
Wszystkie powyższe odpowiedzi są świetne ... Właśnie dodam jedną, o której nikt jeszcze nie wspominał o utrwalaniu danych poprzez działania, a mianowicie użycie wbudowanej bazy danych SQLite dla Androida, aby zachować odpowiednie dane ... W rzeczywistości możesz umieścić swoją databaseHelper w stanie aplikacji i wywołuj go w razie potrzeby podczas aktywacji. Lub po prostu stwórz klasę pomocnika i wykonaj wywołania DB w razie potrzeby ... Wystarczy dodać kolejną warstwę do rozważenia ... Ale wszystkie pozostałe odpowiedzi byłyby wystarczające również .. Naprawdę tylko preferencje
źródło
Udostępnianie danych między działaniami, na przykład przekazywanie wiadomości e-mail po zalogowaniu
„e-mail” to nazwa, za pomocą której można odwoływać się do wartości żądanego działania
1 Kod na stronie logowania
2 kod na stronie głównej
źródło
A jeśli chcesz pracować z obiektem danych, te dwie implementacje są bardzo ważne:
Serializable vs Parcelable
public class User implements Parcelable
sprawdź więcej tutaj
źródło