Cykl życia aktywności

Działania są podstawowym blokiem konstrukcyjnym aplikacji systemu Android i mogą istnieć w wielu różnych stanach. Cykl życia działania rozpoczyna się od utworzenia wystąpienia i kończy się zniszczeniem i obejmuje wiele stanów między nimi. Gdy działanie zmienia stan, wywoływana jest odpowiednia metoda zdarzenia cyklu życia, powiadamiając działanie zbliżającej się zmiany stanu i umożliwiając jej wykonanie kodu w celu dostosowania się do tej zmiany. W tym artykule opisano cykl życia działań i wyjaśniono odpowiedzialność za działanie podczas każdego z tych zmian stanu, które mają być częścią dobrze zachowywanej, niezawodnej aplikacji.

Przegląd cyklu życia działania

Działania to nietypowa koncepcja programowania specyficzna dla systemu Android. W tradycyjnym tworzeniu aplikacji zwykle jest wykonywana statyczna metoda główna, która jest wykonywana w celu uruchomienia aplikacji. Z androidem jednak rzeczy są różne; Aplikacje dla systemu Android można uruchamiać za pośrednictwem dowolnego zarejestrowanego działania w aplikacji. W praktyce większość aplikacji będzie mieć tylko określone działanie określone, które jest określone jako punkt wejścia aplikacji. Jeśli jednak aplikacja ulegnie awarii lub zostanie zakończona przez system operacyjny, system operacyjny może spróbować ponownie uruchomić aplikację w ostatnim otwartym działaniu lub gdziekolwiek indziej w poprzednim stosie działań. Ponadto system operacyjny może wstrzymać działania, gdy nie są aktywne, i odzyskać je, jeśli jest mało pamięci. Należy zachować ostrożność, aby umożliwić aplikacji poprawne przywrócenie stanu w przypadku ponownego uruchomienia działania, zwłaszcza jeśli to działanie zależy od danych z poprzednich działań.

Cykl życia działania jest implementowany jako kolekcja metod wywoływanych przez system operacyjny w całym cyklu życia działania. Te metody umożliwiają deweloperom zaimplementowanie funkcji niezbędnych do spełnienia wymagań dotyczących stanu i zarządzania zasobami aplikacji.

Deweloper aplikacji bardzo ważne jest, aby analizować wymagania poszczególnych działań w celu określenia metod uwidacznianych przez cykl życia działania. Niepowodzenie w tym celu może spowodować niestabilność aplikacji, awarie, wzdęcie zasobu, a nawet niestabilność bazowego systemu operacyjnego.

W tym rozdziale szczegółowo omówiono cykl życia działania, w tym:

  • Stany działań
  • Metody cyklu życia
  • Zachowywanie stanu aplikacji

Ta sekcja zawiera również przewodnik , który zawiera praktyczne przykłady dotyczące efektywnego zapisywania stanu podczas cyklu życia działania. Na koniec tego rozdziału należy poznać cykl życia działania i sposób jego obsługi w aplikacji dla systemu Android.

Cykl życia aktywności

Cykl życia działania systemu Android obejmuje kolekcję metod uwidocznionych w klasie Activity, która zapewnia deweloperowi strukturę zarządzania zasobami. Ta struktura umożliwia deweloperom spełnienie unikatowych wymagań dotyczących zarządzania stanem poszczególnych działań w aplikacji i prawidłowe zarządzanie zasobami.

Stany działań

System operacyjny Android arbitruje działania na podstawie ich stanu. Ułatwia to systemowi Android identyfikowanie działań, które nie są już używane, dzięki czemu system operacyjny może odzyskać pamięć i zasoby. Na poniższym diagramie przedstawiono stany, przez które działanie może przechodzić w okresie jego istnienia:

Activity states diagram

Te stany można podzielić na 4 główne grupy w następujący sposób:

  1. Aktywne lub uruchomione — działania są uznawane za aktywne lub uruchomione, jeśli znajdują się na pierwszym planie, znane również jako górna część stosu działań. Jest to uważane za działanie o najwyższym priorytecie w systemie Android i w związku z tym zostanie zabite tylko przez system operacyjny w skrajnych sytuacjach, na przykład jeśli działanie próbuje użyć więcej pamięci niż jest dostępne na urządzeniu, ponieważ może to spowodować, że interfejs użytkownika przestanie odpowiadać.

  2. Wstrzymano — gdy urządzenie przejdzie w stan uśpienia lub działanie jest nadal widoczne, ale częściowo ukryte przez nową, niezwiązaną z pełnym rozmiarem lub przezroczystą aktywność, działanie jest uznawane za wstrzymane. Wstrzymane działania są nadal aktywne, czyli utrzymują wszystkie informacje o stanie i członkach oraz pozostają dołączone do menedżera okien. Jest to uważane za drugie działanie o najwyższym priorytecie w systemie Android i, w związku z tym, zostanie zabite tylko przez system operacyjny, jeśli zabicie tego działania spełni wymagania dotyczące zasobów wymaganych do utrzymania stabilnej i dynamicznej aktywności aktywnej/uruchomionej.

  3. Zatrzymane/w tle — działania, które są całkowicie zasłonięte przez inne działanie, są uznawane za zatrzymane lub w tle. Zatrzymane działania nadal próbują zachować informacje o stanie i członkach tak długo, jak to możliwe, ale zatrzymane działania są uważane za najniższy priorytet trzech stanów, a w związku z tym system operacyjny najpierw zabije działania w tym stanie, aby spełnić wymagania dotyczące zasobów działań o wyższym priorytcie.

  4. Uruchomiono ponownie — istnieje możliwość usunięcia działania w dowolnym miejscu z wstrzymania do zatrzymania w cyklu życia w celu usunięcia z pamięci przez system Android. Jeśli użytkownik przejdzie z powrotem do działania, które musi zostać ponownie uruchomiony, przywrócony do wcześniej zapisanego stanu, a następnie wyświetlony użytkownikowi.

Ponowne tworzenie działań w odpowiedzi na zmiany konfiguracji

Aby uczynić sprawy bardziej skomplikowane, android rzuca jeszcze jeden klucz w mieszance o nazwie Zmiany konfiguracji. Zmiany konfiguracji to szybkie niszczenie działań/cykle ponownego tworzenia, które występują w przypadku zmiany konfiguracji działania, na przykład gdy urządzenie jest obracane (i działanie musi być ponownie wbudowane w tryb poziomy lub pionowy), gdy jest wyświetlana klawiatura (a działanie jest prezentowane z możliwością zmiany rozmiaru) lub gdy urządzenie jest umieszczone w doku, między innymi.

Zmiany konfiguracji nadal powodują te same zmiany stanu działania, które wystąpią podczas zatrzymywania i ponownego uruchamiania działania. Jednak aby upewnić się, że aplikacja działa szybko i dobrze działa podczas zmian konfiguracji, ważne jest, aby były one obsługiwane tak szybko, jak to możliwe. W związku z tym system Android ma określony interfejs API, który może służyć do utrwalania stanu podczas zmian konfiguracji. Omówimy to w dalszej części sekcji Zarządzanie stanem w całym cyklu życia .

Metody cyklu życia działania

Zestaw SDK systemu Android i platforma platformy Xamarin.Android udostępnia zaawansowany model zarządzania stanem działań w aplikacji. Gdy stan działania ulega zmianie, działanie jest powiadamiane przez system operacyjny, który wywołuje określone metody tego działania. Na poniższym diagramie przedstawiono te metody w odniesieniu do cyklu życia działania:

Activity Lifecycle flowchart

Jako deweloper możesz obsługiwać zmiany stanu, przesłaniając te metody w ramach działania. Należy jednak pamiętać, że wszystkie metody cyklu życia są wywoływane w wątku interfejsu użytkownika i uniemożliwi systemowi operacyjnemu wykonywanie kolejnego fragmentu pracy interfejsu użytkownika, na przykład ukrywanie bieżącego działania, wyświetlanie nowego działania itp. W związku z tym kod w tych metodach powinien być tak krótki, jak to możliwe, aby aplikacja czuła się dobrze. Wszystkie długotrwałe zadania powinny być wykonywane w wątku w tle.

Przyjrzyjmy się każdej z tych metod cyklu życia i ich użyciu:

Oncreate

OnCreate to pierwsza metoda wywoływana podczas tworzenia działania. OnCreate Program jest zawsze zastępowany w celu wykonania wszystkich inicjalizacji uruchamiania, które mogą być wymagane przez działanie, takie jak:

  • Tworzenie widoków
  • Inicjowanie zmiennych
  • Wiązanie danych statycznych z listami

OnCreatePrzyjmuje parametr Bundle, który jest słownikiem do przechowywania i przekazywania informacji o stanie i obiektów między działaniami Jeśli pakiet nie ma wartości null, oznacza to, że działanie jest uruchamiane ponownie i powinno przywrócić jego stan z poprzedniego wystąpienia. Poniższy kod ilustruje sposób pobierania wartości z pakietu:

protected override void OnCreate(Bundle bundle)
{
   base.OnCreate(bundle);

   string intentString;
   bool intentBool;

   if (bundle != null)
   {
      intentString = bundle.GetString("myString");
      intentBool = bundle.GetBoolean("myBool");
   }

   // Set our view from the "main" layout resource
   SetContentView(Resource.Layout.Main);
}

Po OnCreate zakończeniu system Android wywoła metodę OnStart.

Onstart

OnStart jest zawsze wywoływany przez system po OnCreate zakończeniu. Działania mogą przesłonić tę metodę, jeśli muszą wykonać określone zadania bezpośrednio, zanim działanie stanie się widoczne, takie jak odświeżanie bieżących wartości widoków w ramach działania. System Android wywoła natychmiast OnResume po tej metodzie.

OnResume

System wywołuje metodę OnResume , gdy działanie jest gotowe do rozpoczęcia interakcji z użytkownikiem. Działania powinny zastąpić tę metodę, aby wykonywać zadania, takie jak:

  • Zwiększenie szybkości klatek na sekundę (typowe zadanie w tworzeniu gier)
  • Uruchamianie animacji
  • Nasłuchiwanie aktualizacji GPS
  • Wyświetlanie dowolnych odpowiednich alertów lub okien dialogowych
  • Podłączać zewnętrzne programy obsługi zdarzeń

Na przykład poniższy fragment kodu pokazuje, jak zainicjować aparat:

protected override void OnResume()
{
    base.OnResume(); // Always call the superclass first.

    if (_camera==null)
    {
        // Do camera initializations here
    }
}

OnResume jest ważne, ponieważ każda operacja wykonywana w OnPause programie powinna zostać cofniętą w OnResumepliku , ponieważ jest to jedyna metoda cyklu życia gwarantowana do wykonania po OnPause zakończeniu działania.

Onpause

OnPause jest wywoływany, gdy system ma umieścić działanie w tle lub gdy działanie stanie się częściowo zasłonięte. Działania powinny zastąpić tę metodę, jeśli zajdzie taka potrzeba:

  • Zatwierdzanie niezapisanych zmian w danych trwałych

  • Niszczenie lub czyszczenie innych obiektów zużywających zasoby

  • Zwiększ szybkość klatek i wstrzymuje animacje

  • Wyrejestruj zewnętrzne programy obsługi zdarzeń lub programy obsługi powiadomień (tj. te, które są powiązane z usługą). Należy to zrobić, aby zapobiec wyciekom pamięci działania.

  • Podobnie, jeśli działanie wyświetliło jakiekolwiek okna dialogowe lub alerty, należy je wyczyścić za pomocą .Dismiss() metody .

Na przykład poniższy fragment kodu zwolni aparat, ponieważ działanie nie może jej używać podczas wstrzymania:

protected override void OnPause()
{
    base.OnPause(); // Always call the superclass first

    // Release the camera as other activities might need it
    if (_camera != null)
    {
        _camera.Release();
        _camera = null;
    }
}

Istnieją dwie możliwe metody cyklu życia, które będą wywoływane po :OnPause

  1. OnResume zostanie wywołana, jeśli działanie ma zostać zwrócone na pierwszym planie.
  2. OnStop zostanie wywołana, jeśli działanie jest umieszczane w tle.

Onstop

Funkcja OnStop jest wywoływana, gdy działanie nie jest już widoczne dla użytkownika. Dzieje się tak, gdy wystąpi jeden z następujących:

  • Trwa uruchamianie nowego działania i obejmuje to działanie.
  • Istniejące działanie jest wprowadzane na pierwszym planie.
  • Działanie jest niszczone.

OnStop Może nie zawsze być wywoływana w sytuacjach o niskiej ilości pamięci, takich jak gdy system Android jest głodny dla zasobów i nie może prawidłowo w tle działania. Z tego powodu najlepiej nie polegać na OnStop wywoływaniu podczas przygotowywania działania do zniszczenia. Następne metody cyklu życia, które mogą być wywoływane po tym, będzie miało OnDestroy wartość , jeśli działanie zniknie lub OnRestart jeśli działanie wróci do interakcji z użytkownikiem.

OnDestroy

OnDestroy to ostateczna metoda wywoływana w wystąpieniu działania, zanim zostanie zniszczona i całkowicie usunięta z pamięci. W skrajnych sytuacjach system Android może zabić proces aplikacji hostujący działanie, co spowoduje OnDestroy , że nie zostanie wywołany. Większość działań nie zaimplementuje tej metody, ponieważ większość metod czyszczenia i zamykania została wykonana w metodach OnPause i OnStop . Metoda OnDestroy jest zwykle zastępowana w celu oczyszczenia długotrwałych zadań, które mogą wyciekać zasoby. Przykładem mogą być wątki w tle, które zostały uruchomione w pliku OnCreate.

Po zniszczeniu działania nie będą wywoływane żadne metody cyklu życia.

OnRestart

Polecenie OnRestart jest wywoływane po zatrzymaniu działania przed jego ponownym uruchomieniem. Dobrym przykładem może być naciśnięcie przycisku Strona główna przez użytkownika podczas działania w aplikacji. W takim przypadku OnPause metody OnStop są wywoływane, a działanie jest przenoszone do tła, ale nie jest niszczone. Jeśli użytkownik miał następnie przywrócić aplikację przy użyciu menedżera zadań lub podobnej aplikacji, system Android wywoła OnRestart metodę działania.

Nie ma ogólnych wytycznych dotyczących rodzaju logiki, która powinna zostać zaimplementowana w programie OnRestart. Jest to spowodowane tym, że OnStart zawsze jest wywoływana niezależnie od tego, czy działanie jest tworzone, czy ponownie uruchamiane, więc wszelkie zasoby wymagane przez działanie powinny być inicjowane w elemecie , a nie OnRestart.OnStart

Następną metodą cyklu życia o nazwie after OnRestart będzie OnStart.

Powrót a strona główna

Wiele urządzeń z systemem Android ma dwa odrębne przyciski: przycisk "Wstecz" i przycisk "Strona główna". Przykład tego można zobaczyć na poniższym zrzucie ekranu systemu Android 4.0.3:

Back and Home buttons

Istnieje subtelna różnica między dwoma przyciskami, mimo że wydają się mieć taki sam wpływ na umieszczenie aplikacji w tle. Gdy użytkownik kliknie przycisk Wstecz, informuje system Android, że wykonuje działanie. System Android zniszczy działanie. Natomiast gdy użytkownik kliknie przycisk Strona główna, działanie zostanie umieszczone tylko w tle — system Android nie zabije działania.

Zarządzanie stanem w całym cyklu życia

Gdy działanie zostanie zatrzymane lub zniszczone, system będzie miał możliwość zapisania stanu działania na potrzeby późniejszego ponownego wypełniania. Ten zapisany stan jest określany jako stan wystąpienia. System Android udostępnia trzy opcje przechowywania stanu wystąpienia podczas cyklu życia działania:

  1. Przechowywanie wartości pierwotnych w Dictionary pakiecie znanym jako pakiet , którego system Android użyje do zapisania stanu.

  2. Tworzenie niestandardowej klasy, która będzie przechowywać złożone wartości, takie jak mapy bitowe. System Android użyje tej klasy niestandardowej do zapisania stanu.

  3. Obejście cyklu życia zmiany konfiguracji i przyjęcie pełnej odpowiedzialności za utrzymanie stanu w działaniu.

W tym przewodniku omówiono dwie pierwsze opcje.

Stan pakietu

Podstawową opcją zapisywania stanu wystąpienia jest użycie obiektu słownika klucz/wartość nazywanego pakietem. Pamiętaj, że OnCreate po utworzeniu działania metoda jest przekazywana pakiet jako parametr, ten pakiet może służyć do przywrócenia stanu wystąpienia. Nie zaleca się używania pakietu do bardziej złożonych danych, które nie będą szybko ani łatwo serializować par klucz/wartość (takich jak mapy bitowe); zamiast tego należy go używać dla prostych wartości, takich jak ciągi.

Działanie udostępnia metody ułatwiające zapisywanie i pobieranie stanu wystąpienia w pakiecie:

  • OnSaveInstanceState — jest to wywoływane przez system Android, gdy działanie jest niszczone. Działania mogą implementować tę metodę, jeśli muszą utrwalić wszystkie elementy stanu klucz/wartość.

  • OnRestoreInstanceState — jest to wywoływane po zakończeniu OnCreate metody i zapewnia inną możliwość przywrócenia stanu działania po zakończeniu inicjowania.

Na poniższym diagramie przedstawiono sposób użycia tych metod:

Bundle states flowchart

OnSaveInstanceState

Wartość OnSaveInstanceState będzie wywoływana jako działanie jest zatrzymywane. Otrzyma parametr pakietu, w ramach którego działanie może przechowywać jego stan. Gdy urządzenie ulegnie zmianie konfiguracji, działanie może użyć obiektu przekazanego Bundle w celu zachowania stanu działania przez zastąpienie OnSaveInstanceStateelementu . Rozważmy na przykład następujący kod:

int c;

protected override void OnCreate (Bundle bundle)
{
  base.OnCreate (bundle);

  this.SetContentView (Resource.Layout.SimpleStateView);

  var output = this.FindViewById<TextView> (Resource.Id.outputText);

  if (bundle != null) {
    c = bundle.GetInt ("counter", -1);
  } else {
    c = -1;
  }

  output.Text = c.ToString ();

  var incrementCounter = this.FindViewById<Button> (Resource.Id.incrementCounter);

  incrementCounter.Click += (s,e) => {
    output.Text = (++c).ToString();
  };
}

Powyższy kod zwiększa liczbę całkowitą o nazwie c po kliknięciu przycisku o nazwie incrementCounter , wyświetlając wynik w TextView nazwie output. Gdy wystąpi zmiana konfiguracji — na przykład po obróceniu urządzenia — powyższy kod utraci wartość , c ponieważ bundle będzie nullto wartość , jak pokazano na poniższej ilustracji:

Display does not show previous value

Aby zachować wartość w c tym przykładzie, działanie może zastąpić wartość , zapisując wartość w pakiecie OnSaveInstanceState, jak pokazano poniżej:

protected override void OnSaveInstanceState (Bundle outState)
{
  outState.PutInt ("counter", c);
  base.OnSaveInstanceState (outState);
}

Teraz, gdy urządzenie zostanie obrócone do nowej orientacji, liczba całkowita zostanie zapisana w pakiecie i zostanie pobrana przy użyciu wiersza:

c = bundle.GetInt ("counter", -1);

Uwaga

Ważne jest, aby zawsze wywoływać podstawową implementację OnSaveInstanceState , aby można było również zapisać stan hierarchii widoków.

Stan widoku

Zastępowanie OnSaveInstanceState jest odpowiednim mechanizmem zapisywania danych przejściowych w działaniu między zmianami orientacji, takimi jak licznik w powyższym przykładzie. Jednak domyślna implementacja OnSaveInstanceState programu zajmie się zapisywaniem danych przejściowych w interfejsie użytkownika dla każdego widoku, tak długo, jak każdy widok ma przypisany identyfikator. Załóżmy na przykład, że aplikacja ma EditText element zdefiniowany w formacie XML w następujący sposób:

<EditText android:id="@+id/myText"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"/>

Ponieważ kontrolka EditText ma przypisaną id wartość, gdy użytkownik wprowadza pewne dane i obraca urządzenie, dane są nadal wyświetlane, jak pokazano poniżej:

Data is preserved in landscape mode

OnRestoreInstanceState

Wartość OnRestoreInstanceState zostanie wywołana po OnStart. Zapewnia to działanie możliwość przywrócenia dowolnego stanu, który został wcześniej zapisany w pakiecie podczas poprzedniego OnSaveInstanceStateelementu . Jest to jednak ten sam pakiet, który jest dostarczany do OnCreate, jednak.

Poniższy kod pokazuje, jak można przywrócić stan w programie OnRestoreInstanceState:

protected override void OnRestoreInstanceState(Bundle savedState)
{
    base.OnRestoreInstanceState(savedState);
    var myString = savedState.GetString("myString");
    var myBool = savedState.GetBoolean("myBool");
}

Ta metoda istnieje, aby zapewnić pewną elastyczność w przypadku przywrócenia stanu. Czasami bardziej odpowiednie jest poczekanie na ukończenie wszystkich inicjalizacji przed przywróceniem stanu wystąpienia. Ponadto podklasa istniejącego działania może chcieć przywrócić tylko niektóre wartości ze stanu wystąpienia. W wielu przypadkach nie jest konieczne zastąpienie OnRestoreInstanceStateelementu , ponieważ większość działań może przywrócić stan przy użyciu pakietu dostarczonego do OnCreateelementu .

Aby zapoznać się z przykładem zapisywania stanu przy użyciu elementu Bundle, zapoznaj się z przewodnikiem — zapisywanie stanu działania.

Ograniczenia pakietu

Chociaż OnSaveInstanceState ułatwia zapisywanie danych przejściowych, ma pewne ograniczenia:

  • Nie jest wywoływana we wszystkich przypadkach. Na przykład naciśnięcie przycisku Strona główna lub Powrót w celu zakończenia działania nie spowoduje OnSaveInstanceState wywołania.

  • Pakiet przekazany do OnSaveInstanceState elementu nie jest przeznaczony dla dużych obiektów, takich jak obrazy. W przypadku dużych obiektów preferowane jest zapisanie obiektu z onRetainNonConfigurationInstance , jak opisano poniżej.

  • Dane zapisane przy użyciu pakietu są serializowane, co może prowadzić do opóźnień.

Stan pakietu jest przydatny w przypadku prostych danych, które nie używają dużej ilości pamięci, natomiast dane wystąpienia niekonfiguracyjne są przydatne w przypadku bardziej złożonych danych lub danych, które są kosztowne do pobrania, na przykład z wywołania usługi internetowej lub skomplikowanego zapytania bazy danych. Dane wystąpienia niekonfiguracyjne są zapisywane w obiekcie zgodnie z potrzebami. W następnej sekcji przedstawiono OnRetainNonConfigurationInstance sposób zachowania bardziej złożonych typów danych za pomocą zmian konfiguracji.

Utrwalanie złożonych danych

Oprócz utrwalania danych w pakiecie system Android obsługuje również zapisywanie danych przez zastąpienie klasy OnRetainNonConfigurationInstance i zwrócenie wystąpienia elementu zawierającego Java.Lang.Object dane do utrwalania. Istnieją dwie podstawowe korzyści wynikające z używania OnRetainNonConfigurationInstance funkcji do zapisywania stanu:

  • Obiekt zwracany z OnRetainNonConfigurationInstance funkcji działa dobrze z większymi, bardziej złożonymi typami danych, ponieważ pamięć zachowuje ten obiekt.

  • Metoda jest wywoływana OnRetainNonConfigurationInstance na żądanie i tylko wtedy, gdy jest to konieczne. Jest to bardziej ekonomiczne niż korzystanie z ręcznej pamięci podręcznej.

Użycie OnRetainNonConfigurationInstance jest odpowiednie w scenariuszach, w których pobieranie danych jest kosztowne wielokrotnie, na przykład w wywołaniach usługi internetowej. Rozważmy na przykład następujący kod, który wyszukuje w serwisie Twitter:

public class NonConfigInstanceActivity : ListActivity
{
  protected override void OnCreate (Bundle bundle)
  {
    base.OnCreate (bundle);
    SearchTwitter ("xamarin");
  }

  public void SearchTwitter (string text)
  {
    string searchUrl = String.Format("http://search.twitter.com/search.json?" + "q={0}&rpp=10&include_entities=false&" + "result_type=mixed", text);

    var httpReq = (HttpWebRequest)HttpWebRequest.Create (new Uri (searchUrl));
    httpReq.BeginGetResponse (new AsyncCallback (ResponseCallback), httpReq);
  }

  void ResponseCallback (IAsyncResult ar)
  {
    var httpReq = (HttpWebRequest)ar.AsyncState;

    using (var httpRes = (HttpWebResponse)httpReq.EndGetResponse (ar)) {
      ParseResults (httpRes);
    }
  }

  void ParseResults (HttpWebResponse httpRes)
  {
    var s = httpRes.GetResponseStream ();
    var j = (JsonObject)JsonObject.Load (s);

    var results = (from result in (JsonArray)j ["results"] let jResult = result as JsonObject select jResult ["text"].ToString ()).ToArray ();

    RunOnUiThread (() => {
      PopulateTweetList (results);
    });
  }

  void PopulateTweetList (string[] results)
  {
    ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
  }
}

Ten kod pobiera wyniki z sieci Web sformatowanej jako JSON, analizuje je, a następnie przedstawia wyniki na liście, jak pokazano na poniższym zrzucie ekranu:

Results displayed on screen

Gdy wystąpi zmiana konfiguracji — na przykład po obróceniu urządzenia — kod powtarza proces. Aby ponownie użyć pierwotnie pobranych wyników i nie powodować niepotrzebnych, nadmiarowych wywołań sieciowych, możemy użyć OnRetainNonconfigurationInstance polecenia , aby zapisać wyniki, jak pokazano poniżej:

public class NonConfigInstanceActivity : ListActivity
{
  TweetListWrapper _savedInstance;

  protected override void OnCreate (Bundle bundle)
  {
    base.OnCreate (bundle);

    var tweetsWrapper = LastNonConfigurationInstance as TweetListWrapper;

    if (tweetsWrapper != null) {
      PopulateTweetList (tweetsWrapper.Tweets);
    } else {
      SearchTwitter ("xamarin");
    }

    public override Java.Lang.Object OnRetainNonConfigurationInstance ()
    {
      base.OnRetainNonConfigurationInstance ();
      return _savedInstance;
    }

    ...

    void PopulateTweetList (string[] results)
    {
      ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
      _savedInstance = new TweetListWrapper{Tweets=results};
    }
}

Teraz, gdy urządzenie zostanie obrócone, oryginalne wyniki zostaną pobrane z LastNonConfiguartionInstance właściwości . W tym przykładzie wyniki składają się z string[] zawierających tweety. Ponieważ OnRetainNonConfigurationInstance wymaga zwrócenia elementu Java.Lang.Object , string[] element jest opakowany w klasę, która klasy Java.Lang.Object, jak pokazano poniżej:

class TweetListWrapper : Java.Lang.Object
{
  public string[] Tweets { get; set; }
}

Na przykład próba użycia TextView obiektu jako obiektu zwróconego z OnRetainNonConfigurationInstance obiektu spowoduje wyciek działania, jak pokazano w poniższym kodzie:

TextView _textView;

protected override void OnCreate (Bundle bundle)
{
  base.OnCreate (bundle);

  var tv = LastNonConfigurationInstance as TextViewWrapper;

  if(tv != null) {
    _textView = tv;
    var parent = _textView.Parent as FrameLayout;
    parent.RemoveView(_textView);
  } else {
    _textView = new TextView (this);
    _textView.Text = "This will leak.";
  }

  SetContentView (_textView);
}

public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
  base.OnRetainNonConfigurationInstance ();
  return _textView;
}

W tej sekcji przedstawiono sposób zachowywania prostych danych o stanie za Bundlepomocą elementu i utrwalania bardziej złożonych typów danych za pomocą polecenia OnRetainNonConfigurationInstance.

Podsumowanie

Cykl życia działania systemu Android zapewnia zaawansowaną strukturę zarządzania stanami działań w aplikacji, ale może to być trudne do zrozumienia i zaimplementowania. W tym rozdziale przedstawiono różne stany, przez które działanie może przechodzić w okresie jego istnienia, a także metody cyklu życia skojarzone z tymi stanami. Następnie podano wskazówki dotyczące rodzaju logiki, jaką należy wykonać w każdej z tych metod.