Activity.finish () วิธีการทำอะไรกันแน่?


156

ฉันกำลังพัฒนาแอปพลิเคชั่น Android สักระยะหนึ่งและตามมาเป็นจำนวนมากเกี่ยวกับวงจรชีวิตของกิจกรรมและวงจรชีวิตของแอปพลิเคชัน

ฉันรู้ว่าActivity.finish()วิธีการโทรไปที่ไหนสักแห่งActivity.onDestroy()และยังลบกิจกรรมออกจากสแต็คและฉันคิดว่ามันชี้ไปที่ระบบปฏิบัติการและตัวรวบรวมขยะที่เขาสามารถ "ทำกลอุบายของเขา" และเพิ่มหน่วยความจำเมื่อพบว่ามันเป็นเวลาที่ดี ดังนั้น....

ฉันมาที่โพสต์นี้ - จะเลิกสมัครได้หรือไม่? และอ่านคำตอบของ Mark Murphy

มันทำให้ฉันสับสนเล็กน้อยเกี่ยวกับfinish()วิธีการที่แท้จริง

มีโอกาสที่ฉันจะโทรหาfinish()และonDestroy()จะไม่ถูกเรียก?


เธรดที่เกี่ยวข้อง - Activity.finish () ทำงานอย่างไรใน Android
RBT

คำตอบ:


171

เมื่อเรียกfinish()ใช้กิจกรรมonDestroy()จะเรียกใช้เมธอด วิธีนี้สามารถทำสิ่งต่าง ๆ เช่น:

  1. ปิดกล่องโต้ตอบที่กิจกรรมกำลังจัดการอยู่
  2. ปิดเคอร์เซอร์ใด ๆ ที่กิจกรรมกำลังจัดการอยู่
  3. ปิดกล่องโต้ตอบการค้นหาที่เปิดอยู่

นอกจากนี้onDestroy()ไม่ได้เป็นตัวทำลายล้าง มันไม่ได้ทำลายวัตถุจริงๆ มันเป็นเพียงวิธีการที่เรียกว่าขึ้นอยู่กับสถานะที่แน่นอน ดังนั้นอินสแตนซ์ของคุณยังมีชีวิตอยู่และดีมาก * หลังจากการonDestroy()รันและส่งคืนซูเปอร์คลาสแอนดรอยด์คอยประมวลผลในกรณีที่ผู้ใช้ต้องการรีสตาร์ทแอปสิ่งนี้ทำให้ขั้นตอนการเริ่มต้นเร็วขึ้น กระบวนการจะไม่ทำอะไรเลยและหากจำเป็นต้องเรียกคืนหน่วยความจำกระบวนการจะถูกฆ่า


5
ดังนั้นเสร็จสิ้น () วิธีการเท่านั้นเรียกการ onDestroy () และนั่นคือมันได้หรือไม่
Tal Kanel

9
ใช่ถ้าคุณกลับมาที่กิจกรรม onCreate () จะถูกเรียก
Luis Pena

9
Finish () เรียกใช้ onPause () และ onStop () ด้วยหรือไม่
sr09

36
ฉันทดสอบอีกครั้งและพบว่า onPause (), onStop () และ onDestroy () จะถูกเรียกตามลำดับหลังจากที่คุณโทรเสร็จสิ้น ()
Sam003

5
@Laurent onPause () และ onStop () ไม่ได้ถูกเรียกเสมอ ดูการสังเกตของฉันในคำตอบด้านล่าง
Prakash

77

2 เซนต์ของฉันใน @K_Anas คำตอบ ฉันทำการทดสอบอย่างง่ายเมื่อเสร็จสิ้น () วิธี รายการวิธีการโทรกลับที่สำคัญในวงจรชีวิตของกิจกรรม

  1. การโทรเสร็จสิ้น () ใน onCreate (): onCreate () -> onDestroy ()
  2. การโทรเสร็จสิ้น () ใน onStart (): onCreate () -> onStart () -> onStop () -> onDestroy ()
  3. การโทรเสร็จสิ้น () ใน onResume (): onCreate () -> onStart () -> onResume () -> onPause () -> onStop () -> onDestroy ()

สิ่งที่ฉันหมายถึงคือการที่คู่ของวิธีการพร้อมกับวิธีการใด ๆ ในระหว่างที่เรียกว่าเมื่อดำเนินการเสร็จสิ้น ()

เช่น:

 onCreate() counter part is onDestroy()
 onStart() counter part is onStop()
 onPause() counter part is onResume()

เกิดอะไรขึ้นถ้าคุณโทรเสร็จภายใน onPause? มันจะเรียกบน Stop> onDestroy?
rmpt

ตารางนั้นมีประโยชน์จริง ๆ และเป็นคำอธิบาย (คุณต้องเลื่อนลงเล็กน้อย) developer.android.com/reference/android/app/
......

ฉันเองได้ตรวจสอบแล้วว่าคำตอบนี้ถูกต้อง
Sreekanth Karumanaghat

33

โปรดสังเกตว่าถ้าคุณโทรเสร็จ () หลังจากเจตนาคุณไม่สามารถกลับไปที่กิจกรรมก่อนหน้านี้ได้ด้วยปุ่ม "ย้อนกลับ"

startActivity(intent);
finish();

นี่คือข้อมูลที่ฉันต้องการเพราะฉันมีกิจกรรมที่เชื่อมต่อกับไดรฟ์ของ Google เท่านั้นจากนั้นจะทำการตรวจสอบและย้ายไปที่กิจกรรมหลัก (หรือกิจกรรมการตั้งค่าหากมีข้อผิดพลาด) ดังนั้นผู้ใช้ไม่ควร ไม่สามารถย้อนกลับได้
Francesco Marchetti-Stasi

1
@ Francesco Marchetti-Stasi ในกรณีของคุณมันจะดีกว่าที่จะแทนที่ onBackPressed () และไม่เรียก super.onBackPressed () ในนั้นหากผู้ใช้ไม่ควรกลับไป
พอล

13

onDestroy()มีความหมายสำหรับการล้างข้อมูลในขั้นสุดท้าย - เพิ่มทรัพยากรที่คุณสามารถทำได้ด้วยตัวคุณเองปิดการเชื่อมต่อที่เปิดอ่านผู้เขียน ฯลฯ หากคุณไม่ลบล้างมันระบบจะทำสิ่งที่มันทำ

ในอีกทางหนึ่งfinish()เพียงแค่ให้ระบบทราบว่าโปรแกรมเมอร์ต้องการให้กระแสไฟฟ้าActivityเสร็จสิ้น และด้วยเหตุนี้มันจึงเรียกขึ้นมาonDestroy()หลังจากนั้น

สิ่งที่ควรทราบ:

มันไม่จำเป็นว่าเพียงเรียกร้องให้ทริกเกอร์เรียกร้องให้finish() onDestroy()ไม่อย่างที่เราทราบระบบ Android นั้นมีอิสระในการฆ่ากิจกรรมหากรู้สึกว่ามีทรัพยากรที่จำเป็นสำหรับปัจจุบันActivityซึ่งจำเป็นต้องมีอิสระ


1
คุณเขียนเสร็จสิ้น () ให้ระบบทราบว่ากิจกรรมต้องเสร็จสิ้น ดังนั้นจึงเหมือนกับการพูดว่า "do x = บอกให้ระบบทำการ x" วินาทีสิ่ง: จากคำตอบของคุณดูเหมือนว่ามีวิธีที่ฉันจะเรียก finish () และระบบจะตัดสินใจไม่โทร onDestroy ()? เป็นไปได้ไหม?
Tal Kanel

คุณมีส่วนแรกที่ถูกต้อง โทรบอกระบบที่จะเสร็จสิ้นfinish() Activityส่วน "x" ในคำสั่ง do ของคุณคือ "เพื่อเสร็จสิ้น (ทำลาย) Activity" ส่วนที่สองนั้นผิด อันที่จริงฉันไม่ได้ไปที่นั่นสักคำ ฉันได้แก้ไขคำตอบแล้ว onDestroy()ไม่เพียงถูกกระตุ้นโดยfinish()ระบบสามารถเรียกมันด้วยตัวเองเช่นกัน
Kazekage Gaara

1
ฉันเพิ่งอ่านคำตอบเพิ่มเติมจากคุณ สำหรับตอนนี้ฉันได้รับการโหวตคำตอบแล้วสาเหตุที่ฉันพบว่าคำอธิบายของคุณน่าสนใจ แต่ฉันอยากจะดูว่าคนอื่นจะมีอะไรที่จะพูดเกี่ยวกับมันก่อนทำเครื่องหมายว่าเป็น "answerd" ขอบคุณสำหรับตอนนี้ :)
Tal Kanel

ดังนั้นหลังจากเสร็จสิ้น () ตัวแปรทั้งหมดในกิจกรรมนี้จะถูกทำลายใช่มั้ย เมื่อฉันกลับมาที่กิจกรรมนี้อีกครั้งพวกเขาจะถูกประกาศหรือเริ่มต้นใหม่ใช่ไหม
การพนัน Sibbs

3
หมายเหตุ: หากระบบฆ่ากระบวนการ onDestroy อาจไม่ถูกเรียกใช้ developer.android.com/reference/android/app/…
Kevin Lee

9

เสร็จสิ้น () วิธีการจะทำลายกิจกรรมปัจจุบัน คุณสามารถใช้วิธีนี้ในกรณีที่คุณไม่ต้องการให้กิจกรรมนี้โหลดซ้ำแล้วซ้ำอีกเมื่อผู้ใช้กดปุ่มย้อนกลับ โดยทั่วไปจะล้างกิจกรรมจากสแตกปัจจุบัน


8

นอกจากคำตอบ @rommex ด้านบนฉันได้สังเกตเห็นด้วยว่า finish()จะจัดคิวกิจกรรมที่ถูกทำลายและขึ้นอยู่กับลำดับความสำคัญของกิจกรรม

ถ้าฉันโทรfinish()หลังจากonPause()ฉันเห็นonStop()และonDestroy()โทรทันที

ถ้าฉันโทรfinish()หลังจากonStop()ฉันไม่เห็นonDestroy()จนถึง 5 นาทีต่อมา

จากการสังเกตของฉันดูเหมือนว่าเสร็จสิ้นจะเข้าคิวและเมื่อฉันดูที่adb shell dumpsys activity activitiesมันถูกตั้งค่าเป็นfinishing=trueแต่เนื่องจากมันไม่ได้อยู่ในเบื้องหน้าอีกต่อไปมันไม่ได้จัดลำดับความสำคัญสำหรับการทำลายล้าง

โดยสรุปonDestroy()ไม่รับประกันว่าจะถูกเรียก แต่แม้ในกรณีที่มีการเรียกมันอาจล่าช้าได้


5

คำตอบและหมายเหตุต่างๆอ้างว่าเสร็จสิ้น () สามารถข้าม onPause () และ onStop () และดำเนินการโดยตรงบน onDestroy () เพื่อความเป็นธรรมเอกสาร Android เกี่ยวกับเรื่องนี้ ( http://developer.android.com/reference/android/app/Activity.html ) บันทึก "กิจกรรมกำลังสิ้นสุดลงหรือถูกทำลายโดยระบบ" ซึ่งค่อนข้างคลุมเครือ แต่อาจแนะนำว่า เสร็จสิ้น () สามารถข้ามไปยัง onDestroy ()

JavaDoc เมื่อเสร็จสิ้น () ค่อนข้างน่าผิดหวังในทำนองเดียวกัน ( http://developer.android.com/reference/android/app/Activity.html#finish () ) และไม่ได้สังเกตว่าวิธีการใดที่เรียกว่าเป็นการตอบสนองเมื่อเสร็จสิ้น ()

ดังนั้นฉันจึงเขียนมินิแอพด้านล่างซึ่งบันทึกแต่ละรัฐเมื่อเข้า มันมีปุ่มที่เรียกเสร็จ () - เพื่อให้คุณสามารถดูบันทึกของวิธีการที่ได้รับการยิง การทดลองนี้จะแนะนำให้เสร็จสิ้น ()จะเรียก onPause () และ onStop () ด้วย นี่คือผลลัพธ์ที่ฉันได้รับ:

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");
    }

}

3

@ user3282164 ตามวงจรชีวิตของกิจกรรมควรผ่านonPause()-> onStop()-> onDestroy()เมื่อมีการโทรfinish()เมื่อเรียก

แผนภาพไม่แสดงเส้นทางตรงจาก [เรียกใช้กิจกรรม] ไปที่ [onDestroy() ] ที่เกิดจากระบบ

onStop () doc กล่าวว่า " โปรดทราบว่าวิธีนี้อาจไม่เคยถูกเรียกใช้ในสถานการณ์ที่หน่วยความจำเหลือน้อยซึ่งระบบมีหน่วยความจำไม่เพียงพอที่จะทำให้กระบวนการของกิจกรรมของคุณทำงานหลังจากเรียกใช้เมธอด onPause () "


ไม่เห็นอย่างแน่นอน: stackoverflow.com/questions/12655898/ …
ceph3us

2

การศึกษาของฉันแสดงให้เห็นว่าfinish()วิธีการนี้จริง ๆ แล้วทำการทำลายบางอย่างในคิว แต่กิจกรรมจะไม่ถูกทำลายในทันที การทำลายมีกำหนดแม้ว่า

ตัวอย่างเช่นถ้าคุณวางfinish()ในonActivityResult()การเรียกกลับในขณะที่onResume()ยังไม่ได้ทำงานแล้วครั้งแรกที่onResume()จะได้รับการดำเนินการและหลังจากที่onStop()และonDestroy()จะเรียกว่า

หมายเหตุ: onDestroy()อาจจะไม่ได้เรียกว่าที่ทุกคนตามที่ระบุไว้ในเอกสาร


2

การโทรเสร็จใน onCreate () จะไม่โทร onDestroy () โดยตรงตามที่ @prakash กล่าว finish()ดำเนินการจะไม่เริ่มต้นจนกว่าคุณจะกลับมาควบคุม Android

โทรชัย () ในonCreate () : onCreate () -> onStart () -> onResume () หากผู้ใช้ออกจากแอปจะโทร-> onPause () -> onStop () -> onDestroy ()

การโทรเสร็จสิ้น () ในonStart () : onCreate () -> onStart () -> onStop () -> onDestroy ()

การโทรเสร็จสิ้น () ในonResume () : onCreate () -> onStart () -> onResume () -> onPause () -> onStop () -> onDestroy ()

สำหรับการอ้างอิงเพิ่มเติมตรวจสอบดูที่oncreateนี้อย่างต่อเนื่องหลังจากเสร็จ & เกี่ยวกับเสร็จสิ้น ()


0

ดูเหมือนว่าคำตอบเดียวที่ถูกต้องที่นี่จนถึงขณะนี้ได้รับโดย romnex: "onDestroy () อาจไม่ถูกเรียกเลย" แม้ว่าในทางปฏิบัติแล้วในเกือบทุกกรณีจะไม่มีการรับประกัน: เอกสารที่เสร็จสิ้น () เพียงสัญญาว่าผลลัพธ์ของกิจกรรมจะแพร่กระจายกลับไปยังผู้โทร แต่ไม่มีอะไรเพิ่มเติม นอกจากนี้เอกสารประกอบวงจรชีวิตชี้แจงว่ากิจกรรมนั้นสามารถฆ่าได้โดยระบบปฏิบัติการทันทีที่ onStop () เสร็จสิ้น (หรือแม้กระทั่งก่อนหน้านี้ในอุปกรณ์รุ่นเก่า) ซึ่งแม้ว่าจะไม่น่าเป็นไปได้และหาได้ยากดังนั้นในการทดสอบอย่างง่าย อาจถูกฆ่าในขณะที่หรือแม้กระทั่งก่อนที่จะดำเนินการ onDestroy ()

ดังนั้นหากคุณต้องการให้แน่ใจว่างานบางอย่างเสร็จสิ้นเมื่อคุณโทรเสร็จสิ้น () คุณไม่สามารถวางไว้ใน onDestroy () แต่จะต้องทำในสถานที่เดียวกับที่คุณโทรเสร็จ () ก่อนโทรจริง ๆ


-4

เสร็จสิ้น () เพียงแค่ส่งกลับไปที่กิจกรรมก่อนหน้านี้ใน Android หรืออาจเป็นไปได้ว่าคุณกำลังบอกว่ามันจะย้อนกลับไปหนึ่งขั้นตอนในการสมัคร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.