전체 기록 스택을 지우고 Android에서 새로운 활동을 시작하십시오.


332

스택에서 활동을 시작하여 전체 히스토리를 지우는 것이 가능합니까?

그 상황

A-> B-> C 또는 B-> C로 이동하는 활동 스택이 있습니다 (화면 A는 사용자 토큰을 선택하지만 많은 사용자는 단일 토큰 만 가지고 있습니다).

C 화면에서 사용자 B 화면을 무효화하는 작업을 수행 할 수 있으므로 응용 프로그램은 이미 스택에 있는지 여부에 관계없이 A 화면으로 이동하려고합니다. 화면 A는 내 응용 프로그램의 스택에서 유일한 항목이어야합니다.

노트

비슷한 질문이 많이 있지만이 정확한 질문에 대한 답을 찾지 못했습니다. 나는 전화를 시도했다 getParent().finish()-이것은 항상 널 포인터 예외를 초래한다. FLAG_ACTIVITY_CLEAR_TOP활동이 이미 스택에있는 경우에만 작동합니다.

답변:


658

API 레벨 11에서는이를 위해 새로운 의도 플래그가 추가되었습니다 : Intent.FLAG_ACTIVITY_CLEAR_TASK

명확히하기 위해 다음을 사용하십시오.

자바

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);


코 틀린

intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK


불행히도 API lvl <= 10의 경우 아직 깨끗한 해결책을 찾지 못했습니다. "DontHackAndroidLikeThis"솔루션은 참으로 순수 해커입니다. 그렇게하지 말아야합니다. :)

편집 : @ Ben Pearson 의 의견에 따라 API <= 10의 경우 이제 동일한 목적으로 IntentCompat 클래스를 사용할 수 있습니다 . IntentCompat.FLAG_ACTIVITY_CLEAR_TASK플래그를 사용 하여 작업을 지울 수 있습니다 . 따라서 사전 API 레벨 11도 지원할 수 있습니다.


23
명확히하기 위해 이것을 사용하십시오 : intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
user123321

2
Intent.FLAG_ACTIVITY_NEW_TASK없이 응용 프로그램은 때로는 안드로이드 4에 자신을 닫습니다
max4ever

22
- 당신이 사전 API 레벨 11 지원할 수 있도록 IntentCompat는,뿐만 아니라 지금은 분명 작업에 플래그가 developer.android.com/reference/android/support/v4/content/...
벤 피어슨

10
API 레벨이 <10 인 장치에서는 IntentCompat.FLAG_ACTIVITY_CLEAR_TASK가 무시됩니다. developer.android.com/reference/android/support/v4/content/…
David

7
IntentCompat의 플래그는 충돌을 피하기위한 것일뿐 @David가 말한대로 아무것도하지 않습니다.
Sloy

49

사례 1 : 두 가지 활동 A와 B 만 :

여기에서 활동 흐름은 A-> B입니다 .B에서 백 버튼을 클릭하면 응용 프로그램을 닫고 A에서 활동 B를 시작하는 동안 finish ()를 호출하면 android가 활동 A를 Backstack에 저장하지 못하게됩니다. 응용 프로그램의 Loding / Splash 화면.

Intent newIntent = new Intent(A.this, B.class);
startActivity(newIntent);
finish();

사례 2 : 두 가지 이상의 활동 :

A-> B-> C-> D-> B와 같은 흐름이 있고 활동 D에서 오는 동안 활동 B에서 뒤로 버튼을 클릭하는 경우 우리는 사용해야합니다.

Intent newIntent = new Intent(D.this,B.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(newIntent);

여기서 Intent.FLAG_ACTIVITY_CLEAR_TOP 및 Intent.FLAG_ACTIVITY_NEW_TASK 때문에 스택 B가 새 인스턴스가 아닌 백 스택에서 시작되어 스택을 지우고 맨 위로 만듭니다. 따라서 뒤로 버튼을 누르면 전체 응용 프로그램이 종료됩니다.


2
이것은 나를 위해 일했습니다. 나는 모든 활동에 그 깃발을 넣었습니다. 이 액티비티에서 뒤로 버튼은 이전 액티비티로 완벽하게 작동하며 기본 의도 intent intent = new Intent (Intent.ACTION_MAIN); intent.addCategory (Intent.CATEGORY_HOME); intent.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); startActivity (의도); 끝(); 전체 응용 프로그램은 메모리에 있지만 여전히 활성화되지 않은 상태로 닫히고 u를 다시 시작하면 응용 프로그램이 스플래시 화면으로 이동합니다 :)
Rako

이것이 가장 좋은 대답이어야합니다. 누구든지 나와 같은 시나리오를 가지고 있다면 : A-> B-> C-> D-> E-> (B) E-> B에서 결과가 나올 것입니다 : A-> B
Shem Alexis Chavez

39

Android의 최신 버전> = API 16 사용 finishAffinity()

접근 방식은> = API 16에 적합합니다.

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • 새 활동을 시작하는 것과 동일하며 모든 스택을 지 웁니다.
  • 또는 MainActivity / FirstActivity로 다시 시작하십시오.

1
이것은 속임수를 썼고, 깃발은 나를 위해 4.xx에서 작동하지 않았으며 이것은 완벽하게 작동했습니다! 감사합니다
Jonathan Aste

1
목표가 현재 활동을 포함하여 아래의 모든 활동을 완료하고 자체 작업에서 새 활동을 시작하는 것이 목표 인 경우 정답입니다.
ToBe

24

나는 이것에도 몇 시간을 보냈다 ... 그리고 FLAG_ACTIVITY_CLEAR_TOP은 당신이 원하는 것처럼 들린다는 것에 동의합니다 : 시작되는 활동을 제외하고 전체 스택을 지우면 뒤로 버튼이 응용 프로그램을 종료합니다. 그러나 Mike Repass가 언급했듯이 FLAG_ACTIVITY_CLEAR_TOP은 실행중인 활동이 이미 스택에있는 경우에만 작동합니다. 활동이 없으면 플래그는 아무것도하지 않습니다.

무엇을해야합니까? FLAG_ACTIVITY_NEW_TASK를 사용하여 액티비티를 스택에 시작하면 해당 액티비티가 기록 스택에서 새 작업의 시작이됩니다. 그런 다음 FLAG_ACTIVITY_CLEAR_TOP 플래그를 추가하십시오.

이제 FLAG_ACTIVITY_CLEAR_TOP이 스택에서 새로운 활동을 찾으면 모든 것이 지워지기 전에 거기에 있고 풀려납니다.

여기 내 로그 아웃 기능이 있습니다. View 매개 변수는 기능이 첨부 된 버튼입니다.

public void onLogoutClick(final View view) {
    Intent i = new Intent(this, Splash.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(i);
    finish();
}

1
CLEAR_TOP 대신 CLEAR_TASK을 의미합니까?
Andy

14

스택을 변경해서는 안됩니다. Android 뒤로 버튼은 웹 브라우저에서와 같이 작동해야합니다.

나는 그것을 할 수있는 방법을 생각할 수 있지만 꽤 해킹입니다.

  • 활동 singleTaskAndroidManifest 예제 에 추가 하여 활동 을 만드십시오 .

    <activity android:name=".activities.A"
              android:label="@string/A_title"
              android:launchMode="singleTask"/>
    
    <activity android:name=".activities.B"
              android:label="@string/B_title"
              android:launchMode="singleTask"/>
  • 확장 Application어디로 가야의 논리를 개최한다.

예:

public class DontHackAndroidLikeThis extends Application {

  private Stack<Activity> classes = new Stack<Activity>();

  public Activity getBackActivity() {
    return classes.pop();
  }

  public void addBackActivity(Activity activity) {
    classes.push(activity);
  }
}

A에서 B까지:

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(A.class); 
startActivity(this, B.class);

B에서 C로 :

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(B.class); 
startActivity(this, C.class);

C에서 :

If ( shouldNotGoBackToB() ) {
  DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
  app.pop();
}

pop()스택에서 뒤로 버튼을 처리합니다 .

다시 한번, 당신은 이것을해서는 안됩니다 :)


결국 스택을 그대로두고 사용자에게 현재 화면이 유효하지
않다고 알리기 만하면됩니다.

1
안드로이드가 너무 실망해서 이미 이런 식으로 활동 스택을 관리 할 수는 없습니다. 나는 미래의 안드로이드 앱 에서이 솔루션을 사용하고 싶습니다.
Cephron

4
왜 이것이 사용되어서는 안되는지 명확히하기 위해 : 메모리 누수를 만드는 좋은 방법입니다. 어떤 시점에서 OS는 백그라운드 활동을 중단하기로 결정할 수 있지만 Application인스턴스를 가져 오므로 OS는 RAM을 파괴 된 활동으로부터 남겨 둘 수 없습니다.
Vit Khudenko

@Arhimed 다른 문제가 있습니까? 약한 참조 만 유지하여 메모리 누수를 패치 할 수 있습니다.
Navin

1
@Navin 예, 약한 심판으로 누출을 피할 수 있지만 GC 후에 라이브 활동 심판이 없다면 전체 접근법이 쓸모가 없습니다. 다시 한 번-이 작업을 수행하지 마십시오. 이것은 Android에 대한 잘못된 접근 방식입니다.
Vit Khudenko

12

를 사용하여 새 활동을 시작한 직후 에는 현재 활동이 새 활동 뒤에 쌓이지 않도록 startActivity호출 finish()해야합니다.


+1 특정 상황에서 정확히 하나의 활동이 히스토리 스택에 놓이지 않도록하는 훌륭한 솔루션입니다.
marsbear

27
스택에 둘 이상의 액티비티가있는 경우 작동하지 않습니다. 마무리는 이전 액티비티 만 지우고 다른 액티비티는 지 웁니다 ....
Necronet

5

이 시도:

Intent logout_intent = new Intent(DashboardActivity.this, LoginActivity.class);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(logout_intent);
finish();

4

재사용 가능한 고급 Kotlin :

setter 메소드를 사용하여 플래그를 직접 설정할 수 있습니다. 코 틀린에 or는 IS 교체 자바 비트 또는에 대한 |.

intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK

이것을 정기적으로 사용하려는 경우 의도 확장 기능을 작성하십시오.

fun Intent.clearStack() {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

그런 다음 의도를 시작하기 전에이 함수를 직접 호출 할 수 있습니다.

intent.clearStack()

다른 상황에서 추가 플래그를 추가하는 옵션이 필요한 경우 확장 기능에 선택적 매개 변수를 추가하십시오.

fun Intent.clearStack(additionalFlags: Int = 0) {
    flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

2
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);

2

아래 코드를 사용해보십시오.

Intent intent = new Intent(ManageProfileActivity.this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
                Intent.FLAG_ACTIVITY_CLEAR_TASK| 
                Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

이 액티비티를 사용하고 있다면 다시 한 번 api를 호출하지만 기존의 모든 스탯이 지워집니다
Harsha

2

나에게 위의 방법 중 어느 것도 작동하지 않습니다.

이전의 모든 활동지우 려면 다음과 같이하십시오.

finishAffinity() // if you are in fragment use activity.finishAffinity()
Intent intent = new Intent(this, DestActivity.class); // with all flags you want
startActivity(intent)

-1

때로는 안드로이드 에뮬레이터가 Eclipse DDMS 도구를 연결하지 못하고 adb가 수동으로 시작하도록 요청할 수 있습니다. 이 경우 명령 프롬프트를 사용하여 adb를 시작하거나 중지 할 수 있습니다.


1
때로는 안드로이드 에뮬레이터가 Eclipse DDMS 도구를 연결하지 못하고 adb가 수동으로 시작하도록 요청할 수 있습니다. 이 경우 명령 프롬프트를 사용하여 adb를 시작하거나 중지 할 수 있습니다. 의도 i = 새로운 의도 (OldActivity.this, NewActivity.class); // 새 작업을 설정하고 플래그를 지 웁니다. i.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity (i);
RajeshkumarG

-2

나는 너무 간단한 핵을 발견 AndroidManifest했다.

<activity android:name=".activityName"
          android:label="@string/app_name"
          android:noHistory="true"/>

android:noHistory스택에서 원하지 않는 활동을 제거합니다.


2
이 액티비티는이 활동에서 허용을 요청하는 경우 Android 6.0 이상에서 문제를 일으킬 수 있습니다.
Vitaliy A
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.