마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

뒤로가기 버튼 활용하기

0 추천
BackKeyHandler.class를 만들어서 activity.finish();로 mainactivity에서 앱을 종료하는데

다른 액티비티에서 무언갈 수행하고 main으로 오는경우에는 백키하면 전 액티비티로 가는데

이런 경우에는 main에서 어떻게 해야 앱을 종료시킬수 있나요?
enerigpy (2,110 포인트) 님이 2023년 3월 14일 질문

3개의 답변

+1 추천
 
채택된 답변

아래 방법을 시도해 보세요.
 
finishAffinity를 호출하면 현재 task에서 현재 액티비티를 포함 아래에 있는 모든 액티비티를 강제로 닫는다고 합니다.

https://developer.android.com/reference/android/app/Activity.html#finishAffinity()

public class Activity2 extends AppCompatActivity {

    @Override
    public void onBackPressed() {
        finishAffinity();
    }

}

 

spark (230,130 포인트) 님이 2023년 3월 15일 답변
enerigpy님이 2023년 3월 15일 채택됨
감사합니다. 근데 이건 act2로 가야 종료되어서 main에서 손을 봐줘야하네요!
Intent에 FLAG_SINGLE_TOP이나 FLAG_CLEAR_TOP을 사용하시면 백스택을 어느정도 컨트롤 할 수 있느니 Intent에 대한 문서를 살펴보세요.
액티비티를 띄우실 때 FLAG_ACTIVITY_NEW_TASK를 사용하고 계실지도 모르겠다는 의심이 드는데, 혹시 메인액티비티가 두개가 백스택에 존재하는지 확인해 보세요. 메인액티비티가 시작 화면인데 여기서 백키를 누르면 다른 액티비티를 간다는게 정상적인 경우로는 이상해 보여요.
0 추천
질문이 약간 이해가 안되는 부분이 다른 액티비티에서 mainactivity로 오는데 mainactivity에서 백키를 눌렀는데 왜 다른 액티비티로 돌아가나요? mainactivity만 백스택에 존재한다면 당연히 mainactivity만 종료하면 되는데 말이죠.
spark (230,130 포인트) 님이 2023년 3월 14일 답변
spark님이 2023년 3월 14일 수정
음 잘 이해가 되지 않습니다!

Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivityForResult(intent, 0);

이렇게 해봤는데 안되네요
사용법이 조금 다른거같은데요!
지금 어떻게 구현하고 있냐면

main에서 하단바 구현하여 프래그먼트로 이동하고 있고
한 프래그먼트에서 액티비티1 넘어가고 그다음 액티비티2 후에 메인액티비티로 돌아오는거에요
0 추천

액티비만 사용할 때, 프래그먼트만 사용할 때, 두 가지를 복합적으로 사용할 때 모두 백스택의 동작이 다르게 됙기 때문에, 당연히 그럴 수 밖에 없습니다. 짊문을 보면 마치 액티비티 2개를 왔다갔다 하는데 생기는 문제로 보입니다.

먼저 프래그먼트의 백스택이 어떻게 관리되는지 lifecycle이 어떻게 되는지에 대한 기본적인 내용은 알고 가셔야 프래그먼트를 큰 문제없이 사용하실 수 있습니다. 질문 내용으로 봐서는 이 점에 대한 이해가 거의 없으셔서 생기는 의문사항으로 보입니다.

아래 개발자 문서를 먼저 정독해 보시길 권장합니다.

https://developer.android.com/guide/fragments

간단하게 설명을 드리면, 프래그먼트를 백스택에 추가(push)하게 되면, 백키를 누를 때 마다 백스택에 쌓여있던 프래그먼트가 튀어나오게 (pop)게 됩니다. 예를 들면, MainActivity에 A 그리고 B 프래그먼트를 추가하면, 백스택에는 아래처럼 쌓엑 됩니다.

MainActivity

B
___

A

이 때 백키를 누르면, 백스택은 stack이므로 맨위에 있는 B가 나오게 되고, 다시 백키를 누르면 A가 나오게 됩니다. 다시 백키를 누르면 화면에 아무 것도 남지 않고, 다시 백키를 누르면  A를 XML 컴파일타임에 fragment로 추가했을 경우는, 빈화면이 나오지 않고 바로 MainActivity가 종료되고, FragmentManager를 통해 추가한 경우는 빈화면이 나오고 다시 백키를 누를 때 MainActivity가 종료됩니다.

따라서 FragmentManager를 통해 A를 추가했다면, 백스택에 프래그먼트가 남아 있는지 체크해서 없으면 종료를 시켜주셔야 합니다. 만약 이 부분을 커스터마이즈 하고 싶으면 MainActvity의  onBackPressed를 오버라이드 하거나

public class MainActivity extends AppCompatActivity {

    // ...

    @Override
    public void onBackPressed() {
        // Get the FragmentManager
        FragmentManager fragmentManager = getSupportFragmentManager();

        // Check if there are any Fragments on the back stack
        if (fragmentManager.getBackStackEntryCount() > 0) {
            // If there are, pop the back stack to remove the Fragments
            fragmentManager.popBackStack();
        } else {
            // If there aren't, finish the Activity to close the app
            finish();
        }
    }

    // ...
}

한번에  프래그먼트들을 백스택에서 제거하고 싶다면 popBackStack 메소드를 사용하시면 됩니다.

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

프래그먼트 백스택 변경에 대한 처리가 필요하시면 FragmentManager.OnBackStackChangedListener를 사용하시면 됩니다.

public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportFragmentManager().addOnBackStackChangedListener(this);
    }

    @Override
    public void onBackStackChanged() {
        
    }
}

 

프래그먼트는 복잡한 컴포넌트입니다. 기본적인 사항을 충분히 숙지하시는게 좋습니다.

spark (230,130 포인트) 님이 2023년 3월 15일 답변
메인 fragmentManager.popBackStack(); 을 넣어주었는데 안되네요!

@Override
    public void onBackPressed() {
        fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        backKeyHandler.onBackPressed("\'뒤로\' 버튼을 한 번 더 누르시면 종료됩니다.");
    }

직전 액티비티로 돌아가는데 직전 액티비티에서는

startActivityForResult(intent, 0); 이걸 넣어보기도 하고 startactivity 둘다 해봤구요!
백키를 누를 때 백스택이 어떤 상태인지 체크해 보세요. 안닫히는 이유는 백스택에 무언가 들어있기 때문이예요.
그리고 안드로이드 SDK에
https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher
클래스가 이미 존재하니 참고하세요.
프레그먼트에 대한 취소가 아닌 액티비티 뒤로가기 하는걸 취소를 구현하려고 하는데 제가 생각하기엔 답변주신건 그게 아닌거같아서요!
동작구현은 main에서 프래그먼트로 화면전환하고 있고 한 프레그먼트에서 액티비티1로 들어가고 액티비티1에서 액티비티2로 넘어가고 액티비티2에서 메인으로 돌아오는건데 여기서 뒤로가기 하면 액티비티2로 가는걸 막고 앱 종료구현이 목표입니다
MainActivity가 프래그먼트들을 가지고 있다고 하셨는데, 아닌가요? 프래그먼트를 가진 액티비티는 백스택때문에 바로 뒤로가기가 안돼요.
아뇨 프레그먼트에서 액티비티로 넘어가는게 아니면 뒤로가기 해서 종료는 됩니다!
Activity2에서 바로 앱을 종료하고 싶다는 말인가요?

Activity2를 띄울 때 MainActivity를 종료하시던가 아니면, MainActivity로 돌아올 때 종료하도록 값을 Intent 등을 통해 전달해야겠죠.
네 그래서 act2에서 main으로 왔을때 뭘로 구현해야하는지 질문드렸던거에요!
기본적으로 두가지 정도로 구현이 가능합니다.
1. MainAcvity -> startActivityForResult -> Activity1 -> startActivityForResult -> Activity2


2. MainActivity가 single instance 이어야 하므로 launchMode 를 "singleInstance" 으로 설정.(설정방법 참조: https://developer.android.com/guide/topics/manifest/activity-element#lmode)
Activity2 에서 MainActivity로 돌아갈 때
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("shouleExitApp", true);
startActivity(intent);

MainActivity의 onNewIntent를 오버라이드.

@Override
protected void onNewIntent (Intent intent) {
     boolean shouldExitApp = intent.getBooleanExtra("shouldExitApp", false);
     if (shouldExitApp) {
         this.finish();
     }
}

onNewIntent에 대한 설명도 참조하시고
https://developer.android.com/reference/android/app/Activity#onNewIntent(android.content.Intent)
테스트는 안된 코드이므로 필요한 부분은 수정해서 사용하시기 바랍니다.
...