Co dokładnie robi metoda Activity.finish ()?

156

Od jakiegoś czasu tworzę aplikacje na Androida i śledziłem wiele postów na temat cyklu życia aktywności i cyklu życia aplikacji.

Wiem, że Activity.finish()metoda wywołuje gdzieś na drodze Activity.onDestroy(), a także usuwa aktywność ze stosu i wydaje mi się, że to w jakiś sposób wskazuje na system operacyjny i garbage collectora, że ​​może "zrobić swoją sztuczkę" i uwolnić pamięć, gdy uzna to za dobry czas więc....

Doszedłem do tego postu - Czy rezygnacja z aplikacji nie jest mile widziana? i przeczytaj odpowiedź Marka Murphy'ego.

Trochę mnie to zdezorientowało, co finish()właściwie robi ta metoda.

Czy jest szansa, że ​​zadzwonię finish()i onDestroy()nie zadzwonię?

Tal Kanel
źródło

Odpowiedzi:

171

Podczas wywoływania finish()działania metoda onDestroy()jest wykonywana. Ta metoda może wykonywać następujące czynności:

  1. Zamknij wszystkie okna dialogowe, którymi zarządzała aktywność.
  2. Zamknij wszystkie kursory, którymi zarządzała aktywność.
  3. Zamknij wszystkie otwarte okna wyszukiwania

Nie onDestroy()jest też niszczycielem. W rzeczywistości nie niszczy obiektu. To tylko metoda, która jest wywoływana w oparciu o określony stan. Twoja instancja nadal onDestroy()działa i działa bardzo dobrze * po uruchomieniu i powrocie nadklasy.Android utrzymuje procesy na wypadek, gdyby użytkownik chciał ponownie uruchomić aplikację, co przyspiesza fazę uruchamiania. Proces nie będzie nic robić i jeśli trzeba będzie odzyskać pamięć, proces zostanie zabity

K_Anas
źródło
5
więc metoda finish () wyzwalająca tylko wywołanie onDestroy () i to wszystko?
Tal Kanel
9
Tak, jeśli wrócisz do Activity onCreate () zostanie wywołana.
Luis Pena
9
Czy finish () wywołuje również onPause () i onStop ()?
sr09
36
Przetestowałem ponownie i stwierdziłem, że onPause (), onStop () i onDestroy () będą wywoływane po kolei po wywołaniu finish ().
Sam003
5
@Laurent onPause () i onStop () nie zawsze są wywoływane. Zobacz moją obserwację w poniższej odpowiedzi
Prakash
77

Moje 2 centy za odpowiedź @K_Anas. Wykonałem prosty test na metodzie finish (). Wymieniono ważne metody wywołania zwrotnego w cyklu życia działania

  1. Wywołanie finish () w onCreate (): onCreate () -> onDestroy ()
  2. Wywołanie finish () w onStart (): onCreate () -> onStart () -> onStop () -> onDestroy ()
  3. Wywołanie finish () w onResume (): onCreate () -> onStart () -> onResume () -> onPause () -> onStop () -> onDestroy ()

Chcę przez to powiedzieć, że odpowiedniki metod wraz z metodami pośrednimi są wywoływane po wykonaniu metody finish ().

na przykład:

 onCreate() counter part is onDestroy()
 onStart() counter part is onStop()
 onPause() counter part is onResume()
Prakash
źródło
co jeśli zadzwonisz do końca w środku onPause? wywoła onStop> onDestroy?
rmpt
Ta tabela jest naprawdę przydatna i opisowa (trzeba trochę przewinąć w dół) developer.android.com/reference/android/app/ ...
winklerrr
Sam sprawdziłem, że ta odpowiedź jest poprawna.
Sreekanth Karumanaghat,
33

Zauważ również, że jeśli wywołasz finish () po zamianie, nie możesz wrócić do poprzedniej czynności za pomocą przycisku „Wstecz”

startActivity(intent);
finish();
Dan ubiera się u Prady
źródło
To jest dokładnie ta informacja, której potrzebowałem, ponieważ mam aktywność, która łączy się tylko z dyskiem Google, a następnie sprawdza i przechodzi do głównej czynności (lub do działania Ustawienia, jeśli wystąpi błąd), więc użytkownik nie powinien nie będę mógł wrócić.
Francesco Marchetti-Stasi
1
@Francesco Marchetti-Stasi W twoim przypadku lepiej byłoby nadpisać onBackPressed () i nie wywoływać w nim super.onBackPressed (), jeśli użytkownik nie powinien wracać.
Paul
13

onDestroy()jest przeznaczony do ostatecznego czyszczenia - uwolnienia zasobów, które możesz samodzielnie, zamykania otwartych połączeń, czytelników, pisarzy itp. Jeśli tego nie zmienisz, system zrobi to, co powinien.

z drugiej strony, finish()po prostu informuje system, że programista chce, aby prąd Activityzostał zakończony. I dlatego jest wywoływany onDestroy()później.

Coś do zapamiętania:

nie jest konieczne, aby tylko wywołanie finish()wyzwalało wywołanie onDestroy(). Nie. Jak wiemy, system android może zabijać działania, jeśli czuje, że prąd potrzebuje zasobów, Activityktóre trzeba uwolnić.

Kazekage Gaara
źródło
1
napisałeś, że finish () informuje system o konieczności zakończenia działania. więc to tak, jakby powiedzieć „zrób x = powiedz systemowi, aby zrobił x”. sekunda: z twojej odpowiedzi wydaje się, że istnieje sposób wywołania finish (), a system zdecyduje, że nie będzie wywoływał onDestroy ()? Czy to możliwe?
Tal Kanel
Pierwsza część jest dobra. Wywołanie finish()mówi systemowi, aby zakończył Activity. częścią "x" w twojej instrukcji do jest "zakończenie (zniszczenie) Activity". Druga część jest błędna. Właściwie to przegapiłem tam słowo. Poprawiłem odpowiedź. onDestroy()jest nie tylko wyzwalany przez finish()system, ale także może go wywołać samodzielnie.
Kazekage Gaara
1
Właśnie przeczytałem twój dodatek do odpowiedzi. na razie przegłosowałem odpowiedź, ponieważ uważam, że twoje wyjaśnienie jest interesujące, ale chciałbym sprawdzić, czy inni mieliby coś do powiedzenia na ten temat, zanim oznaczysz to jako „odpowiedz”. dzięki na teraz :)
Tal Kanel
Więc po finish () wszystkie zmienne w tej aktywności zostaną zniszczone, prawda? Kiedy wrócę do tej czynności ponownie, zostaną one ponownie zadeklarowane lub zainicjowane, prawda?
Sibbs Gambling,
3
Uwaga: jeśli system zabije proces, nie można wywołać onDestroy. developer.android.com/reference/android/app/…
Kevin Lee
9

Metoda Finish () zniszczy bieżącą aktywność. Możesz użyć tej metody w przypadkach, gdy nie chcesz, aby to działanie było ładowane wielokrotnie, gdy użytkownik naciśnie przycisk Wstecz. Zasadniczo usuwa aktywność z bieżącego stosu.

Udit Kapahi
źródło
8

Oprócz powyższej odpowiedzi @rommex zauważyłem również, że finish()powoduje to kolejkowanie zniszczenia działania i zależy to od priorytetu działania.

Jeśli zadzwonię finish()później onPause(), widzę onStop()i onDestroy()natychmiast dzwonię .

Jeśli zadzwonię finish()później onStop(), widzę onDestroy()dopiero 5 minut później.

Z mojej obserwacji wygląda na to, że wykończenie jest adb shell dumpsys activity activitiesustawione w kolejce, a kiedy spojrzałem na to, było ustawione na finishing=true, ale ponieważ nie jest już na pierwszym planie, nie było priorytetem do zniszczenia.

Podsumowując, onDestroy()nigdy nie ma gwarancji, że zostaniesz wezwany, ale nawet w przypadku wywołania może to zostać opóźnione.

Brandon Lim
źródło
5

Różne odpowiedzi i notatki twierdzą, że finish () może pomijać onPause () i onStop () i bezpośrednio wykonywać onDestroy (). Aby być uczciwym, dokumentacja Androida w tym ( http://developer.android.com/reference/android/app/Activity.html ) zawiera uwagi „Aktywność kończy się lub jest niszczona przez system”, co jest dość niejednoznaczne, ale może sugerować, że finish () może przejść do onDestroy ().

JavaDoc on finish () jest podobnie rozczarowujący ( http://developer.android.com/reference/android/app/Activity.html#finish () ) i tak naprawdę nie zauważa, jakie metody są wywoływane w odpowiedzi na finish ().

Więc napisałem tę mini-aplikację poniżej, która rejestruje każdy stan po wejściu. Zawiera przycisk, który wywołuje finish () - dzięki czemu można zobaczyć dzienniki uruchomionych metod. Ten eksperyment sugerowałby, że finish () rzeczywiście wywołuje również onPause () i onStop (). Oto wynik, który otrzymuję:

2170-2170/? D/LIFECYCLE_DEMO INSIDE: onCreate
2170-2170/? D/LIFECYCLE_DEMO INSIDE: onStart
2170-2170/? D/LIFECYCLE_DEMO INSIDE: onResume
2170-2170/? D/LIFECYCLE_DEMO User just clicked button to initiate finish() 
2170-2170/? D/LIFECYCLE_DEMO INSIDE: onPause
2170-2170/? D/LIFECYCLE_DEMO INSIDE: onStop 
2170-2170/? D/LIFECYCLE_DEMO INSIDE: onDestroy

package com.mvvg.apps.lifecycle;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

public class AndroidLifecycle extends Activity {

    private static final String TAG = "LIFECYCLE_DEMO";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "INSIDE: onCreate");
        setContentView(R.layout.activity_main);
        LinearLayout layout = (LinearLayout) findViewById(R.id.myId);
        Button button = new Button(this);
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View view) {
                Toast.makeText(AndroidLifecycle.this, "Initiating finish()",
                        Toast.LENGTH_SHORT).show();
                Log.d(TAG, "User just clicked button to initiate finish()");
                finish();
            }

        });

        layout.addView(button);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "INSIDE: onStart");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "INSIDE: onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "INSIDE: onDestroy");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "INSIDE: onPause");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "INSIDE: onResume");
    }

}
CoderOfTheNight
źródło
3

@ user3282164 Zgodnie z cyklem życia działania powinno przejść onPause()-> onStop()-> onDestroy()po wywołaniu finish().

Diagram nie pokazuje żadnej prostej ścieżki od [Activity Running] do [ onDestroy()] spowodowanej przez system.

Dokument onStop () mówi: „ Zauważ, że ta metoda może nigdy nie zostać wywołana, w sytuacjach z małą ilością pamięci, gdy system nie ma wystarczającej ilości pamięci, aby utrzymać działanie procesu aktywności po wywołaniu metody onPause () ”.

Meryan
źródło
NIE DOKŁADNIE zobacz: stackoverflow.com/questions/12655898/…
ceph3us
2

Moje badanie pokazuje, że finish()metoda faktycznie umieszcza w kolejce pewne operacje niszczenia, ale działanie nie jest niszczone natychmiast. Planowane jest jednak zniszczenie.

Na przykład, jeśli umieścisz finish()w onActivityResult()zwrotnego, natomiast onResume()musi jeszcze działać, to najpierw onResume()zostanie wykonany, a dopiero później onStop()i onDestroy()są nazywane.

UWAGA: onDestroy()nie można w ogóle dzwonić, jak podano w dokumentacji .

rommex
źródło
2

wywołanie finish w onCreate () nie wywoła bezpośrednio onDestroy (), jak powiedział @prakash. finish()Operacja nie będzie nawet zacząć, aż wrócisz do kontroli Androida.

Wywołanie finish () w onCreate () : onCreate () -> onStart () -> onResume () . Jeśli użytkownik wyjdzie, aplikacja zadzwoni -> onPause () -> onStop () -> onDestroy ()

Wywołanie finish () w onStart () : onCreate () -> onStart () -> onStop () -> onDestroy ()

Wywołanie finish () w onResume () : onCreate () -> onStart () -> onResume () -> onPause () -> onStop () -> onDestroy ()

Aby uzyskać dalsze informacje, spójrz na to oncreate continuous after finish & about finish ()

anand krish
źródło
0

Wygląda na to, że jedyną poprawną odpowiedzią jak dotąd udzielił tu romnex: "onDestroy () nie może w ogóle zostać wywołany". Mimo że w praktyce prawie we wszystkich przypadkach tak się stanie, nie ma żadnej gwarancji: dokumentacja na finish () tylko obiecuje, że wynik działania jest propagowany z powrotem do wywołującego, ale nic więcej. Ponadto dokumentacja cyklu życia wyjaśnia, że ​​działanie jest możliwe do zabicia przez system operacyjny, gdy tylko onStop () zakończy się (lub nawet wcześniej na starszych urządzeniach), co, chociaż mało prawdopodobne, a zatem rzadkie do zaobserwowania w prostym teście, może oznaczać, że działanie może zostać zabity podczas lub nawet przed wykonaniem onDestroy ().

Więc jeśli chcesz mieć pewność, że jakaś praca zostanie wykonana podczas wywoływania finish (), nie możesz jej umieścić w onDestroy (), ale będziesz musiał to zrobić w tym samym miejscu, w którym wywołujesz finish (), tuż przed wywołaniem go.

urps
źródło
-4

finish () po prostu odsyła z powrotem do poprzedniej aktywności w Androidzie lub możesz powiedzieć, że cofa się o jeden krok w aplikacji

kapil
źródło