Erzwingen Sie einen Neustart der Anwendung bei der ersten Aktivität

75

Aus einem unbekannten Grund kann ich meine Anwendung nicht ordnungsgemäß verlassen. Wenn ich die Home-Taste und das App-Symbol erneut drücke, setze ich meine Position in der App fort. Ich möchte die Anwendung zwingen, bei der ersten Aktivität neu zu starten.

Ich nehme an, das hat etwas mit onDestroy () oder vielleicht onPause () zu tun, aber ich weiß nicht, was ich tun soll.

Sephy
quelle

Antworten:

156

Hier ist ein Beispiel, um Ihre App mithilfe des PackageManager generisch neu zu starten:

Intent i = getBaseContext().getPackageManager()
             .getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
Marc
quelle
3
Es hilft mir. Danke. Ich habe so verwendet: "try {Intent i; i = getBaseContext (). GetPackageManager () .getLaunchIntentForPackage (getBaseContext (). GetPackageName ()); i.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity (i);} e) {e.printStackTrace ();}
tknv
Ein Problem bei diesem Ansatz. onCreate der neuen Aktivität wird aufgerufen, bevor der alte Aktivitätsstapel aktiviert wird. Destroy
AAverin
1
@AAverin: Wie kann ich onDestroy vor onCreate aufrufen lassen?
Oligofren
7
funktioniert nicht, nur in der
2
Verwenden Sie Flags als Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK, dies funktioniert hervorragend und löscht auch den Aktivitätsstapel.
Lalit Fauzdar
30

Die als "Antwort" gekennzeichnete Lösung funktioniert, hat jedoch einen für mich entscheidenden Nachteil. Mit FLAG_ACTIVITY_CLEAR_TOP wird Ihre Zielaktivität onCreate aufgerufen, bevor Ihr alter Aktivitätsstapel onDestroy empfängt. Während ich in onDestroy einige notwendige Dinge geklärt habe, musste ich laut arbeiten.

Dies ist die Lösung, die für mich funktioniert hat:

public static void restart(Context context, int delay) {
    if (delay == 0) {
        delay = 1;
    }
    Log.e("", "restarting app");
    Intent restartIntent = context.getPackageManager()
            .getLaunchIntentForPackage(context.getPackageName() );
    PendingIntent intent = PendingIntent.getActivity(
            context, 0,
            restartIntent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
    AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    manager.set(AlarmManager.RTC, System.currentTimeMillis() + delay, intent);
    System.exit(2);
}

Die Idee ist, einen PendingIntent über AlarmManager auszulösen, der etwas später aufgerufen wird, sodass der alte Aktivitätsstapel einige Zeit zum Löschen hat.

AAverin
quelle
1
Warum gehst du nicht einfach den Anruf Activitys‘ finish()Methode statt System.exit? Der Arzt sagt: "Rufen Sie dies an, wenn Ihre Aktivität abgeschlossen ist und geschlossen werden sollte."
Oligofren
1
Ich habe gerade festgestellt, dass die Methode statisch ist und daher keine nicht statischen Methoden wie z finish. Ich habe gerade restartnicht statisch gemacht und stattdessen den System.exit-Aufruf ersetzt.
Oligofren
1
Und nach dem Testen fand ich heraus, dass die Verwendung von finish () dazu führt, dass meine App beim Start hängen bleibt, während System.exit einwandfrei funktioniert ...
oligofren
3
stimme dem vorherigen Kommentar zu. Ich habe PendingIntent.FLAG_CANCEL_CURRENT anstelle von Intent.FLAG_ACTIVITY_CLEAR_TOP verwendet, um die Warnung zu entfernen
Alexeev Valeriy
15

Wenn Sie immer am Stamm beginnen möchten, möchten Sie android: clearTaskOnLaunch für Ihre Stammaktivität auf true setzen

jqpubliq
quelle
1
Ja, das habe ich versucht, aber wenn ich erneut auf das Symbol klicke, scheint es Resume anstelle von onCreate aufzurufen ... was bedeutet, dass ich einen Bildschirm bekomme, ohne dass eine meiner Methoden startet
Sephy
2
Oder fügen Sie das Flag Intent.FLAG_ACTIVITY_CLEAR_TASKprogrammgesteuert zur Absicht hinzu.
Davideas
9
android:clearTaskOnLaunch="true"
android:launchMode="singleTask"

Verwenden Sie diese Eigenschaft in der Manifestdatei in der Startklasse (erste Aktivität).

Rishi Gautam
quelle
3

Tut FLAG_ACTIVITY_CLEAR_TOP das, was Sie tun müssen?

Intent i = new Intent(getBaseContext(), YourActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
Bert
quelle
3

FLAG_ACTIVITY_CLEAR_TOPhat bei mir nicht funktioniert, weil ich 2.3.3 unterstützen musste. Meine erste Lösung war:

Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
    intent.addFlags(Build.VERSION.SDK_INT >= 11 ? Intent.FLAG_ACTIVITY_CLEAR_TASK : Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);

Das funktioniert fast, aber nicht ganz.

Da ich eine Basisaktivität habe, habe ich eine Kill-Sendung hinzugefügt, die alle meine laufenden Aktivitäten schließt.

public abstract class BaseActivity extends AppCompatActivity {

    private static final String ACTION_KILL = "BaseActivity.action.kill";
    private static final IntentFilter FILTER_KILL;
    static {
        FILTER_KILL = new IntentFilter();
        FILTER_KILL.addAction(ACTION_KILL);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        registerReceiver(killReceiver, FILTER_KILL);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(killReceiver);
    }

    private final BroadcastReceiver killReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    };

    public void killApp(){
        sendBroadcast(new Intent(ACTION_KILL));
    }
}

Alle meine Aktivitäten erstrecken sich also von dieser Klasse

((BaseActivity)getActivity()).killApp();
startActivity(new Intent(getActivity(), StartActivity.class));

startet die App neu. Getestet auf Genymotion v10, v16, v21 und Nexus 5 mit v22.

Bearbeiten: Dadurch wird eine Aktivität nicht entfernt, wenn sie zum Zeitpunkt des Sendens der Absicht zerstört wurde. Ich suche immer noch nach einer Lösung.

DariusL
quelle
3

Der folgende Code ist Arbeit für mich, es kann die vollständige App perfekt neu starten!

Intent mStartActivity = new Intent(context, StartActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context,mPendingIntentId,    mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
Beatrice Lin
quelle
Was bedeutet der Wert von mPendingIntentId? Sieht nach einer besonders magischen Zahl aus - ist es nur ein beliebiger Int?
aaaidan
Es ist nur eine beliebige Zahl, Sie können eine beliebige Ganzzahl verwenden. Es ist eine Nachrichtennummer in der PendingIntent-Klasse.
Beatrice Lin
2

Marc's Antwort funktioniert großartig, außer in meinem Fall, in dem meine Hauptaktivität einen launchMode von singleTop hat. Sobald ich diese Absicht ausgeführt habe und dann zu neuen Aktivitäten navigiere und die Home-Taste auf dem Gerät drücke. Dann starte ich meine App erneut über das App-Symbol. Am Ende erstelle ich eine neue Instanz der Hauptaktivität mit meiner vorherigen Aktivität auf dem Backstack .

Nach dieser Frage liegt es daran, dass die Absichten nicht übereinstimmen. Anschauenadb dumpsys activity ich mir das ansehe, sehe ich, dass das Paket in meinem Standard-Android-Launcher null ist, während das Intent-Paket der Name meines Pakets ist, wenn ich das mache, was Marc vorschlägt. Dieser Unterschied führt dazu, dass sie nicht übereinstimmen und eine neue Instanz starten, wenn das App-Symbol erneut getippt wird und die Hauptaktivität nicht oben angezeigt wird.

Bei anderen Startern wie dem Kindle ist das Paket jedoch auf die Absicht des Starters eingestellt, sodass ich eine generische Methode für den Umgang mit Startern benötigte. Ich habe statische Methoden wie die folgenden hinzugefügt:

static boolean mIsLaunchIntentPackageNull = true;    

public static boolean isLaunchIntent(Intent i) {
    if (Intent.ACTION_MAIN.equals(i.getAction()) && i.getCategories() != null
            && i.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
        return true;
    }

    return false;
}

public static void handleLaunchIntent(Intent i) {
    if (isLaunchIntent(i)) {
        if (i.getPackage() != null) {
            mIsLaunchIntentPackageNull = false;
        }
        else {
            mIsLaunchIntentPackageNull = true;
        }
    }
}

mit einem Go-Home-Mechanismus wie diesem:

    Intent intentHome = appContext.getPackageManager()
            .getLaunchIntentForPackage( appContext.getPackageName());
    intentHome.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    // need to match launcher intent exactly to avoid duplicate activities in stack
    if (mIsLaunchIntentPackageNull) {
        intentHome.setPackage(null);
    }
    appContext.startActivity(intentHome);

Dann habe ich in der in meinem Manifest definierten Hauptaktivität folgende Zeile hinzugefügt:

public void onCreate(Bundle savedInstanceState) {
    [class from above].handleLaunchIntent(getIntent());

Dies funktioniert für mich auf Kindle und meinem Telefon und ermöglicht es mir, die App ordnungsgemäß zurückzusetzen, ohne eine weitere Instanz der Hauptaktivität hinzuzufügen.

Mike Venzke
quelle
2

Sie können Jake Whartons lib ProcessPhoenix verwenden, um Ihren Bewerbungsprozess neu zu starten.

mol
quelle
1

das hat bei mir funktioniert:

Intent mStartActivity = new Intent(ctx.getApplicationContext(), ActivityMain.class);


    mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    mStartActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        mStartActivity.addFlags(0x8000); // equal to Intent.FLAG_ACTIVITY_CLEAR_TASK

   int mPendingIntentId = 123456;


    PendingIntent mPendingIntent = PendingIntent.getActivity(ctx, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager mgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, mPendingIntent);

    ActivityManager manager =  (ActivityManager) ctx.getApplicationContext().getSystemService(ctx.getApplicationContext().ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> activityes = ((ActivityManager)manager).getRunningAppProcesses();




    ((Activity)ctx).moveTaskToBack(true);
    manager.killBackgroundProcesses("com.yourpackagename");
    System.exit(0);
Veljko Milisavljević
quelle
0

Sie sollten diese Frage überprüfen:

Programmgesteuertes Neustarten der Android-App

Der Weg dazu ist:

private void restartApp() 
{
   Intent intent = new Intent(getApplicationContext(), YourStarterActivity.class);
   int mPendingIntentId = MAGICAL_NUMBER;
   PendingIntent mPendingIntent = PendingIntent.getActivity(getApplicationContext(), mPendingIntentId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
   AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
   mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
   System.exit(0);
}
Yonatan Nir
quelle
-1

Nach langem Überlegen und Testen habe ich endlich die richtige Möglichkeit, meine Aktivität aufzurufen, um sie neu zu erstellen, wenn die App mit der Home-Taste belassen wird:

android:clearTaskOnLaunch

im Manifest

@Override
public void onRestart(){
    onCreate();
}

Das macht den Trick ... (besser als wenn es in onResume eingefügt wird, das jedes Mal aufgerufen wird, wenn Sie die App starten, sogar beim ersten Mal, was zu einer doppelten Anzeige führt)

Sephy
quelle
2
Das hört sich schlecht an. Sie sollten nur das clearTaskOnLaunchAttribut benötigen . Wie starten Sie Ihre App überhaupt? Direkt von Eclipse mit den ADT-Tools? In diesem Fall gab es einen Fehler, der dazu führte, dass Apps von Eclipse nicht ordnungsgemäß gestartet wurden. Es wurde seitdem behoben.
Christopher Orr
Ja, direkt von Eclipse. aber ich habe es nur mit clearTaskOnLaunch versucht, und ich konnte es nicht zum Laufen bringen ...
Sephy
Hallo, wie man onRestart()Methode hinzufügt . Können Sie einen Ausschnitt geben? Danke
4
Leute, bitte nicht anrufen onCreate()von onRestart(). Dies (Erstellung und Neustart) sind zwei verschiedene Ereignisse. Wenn Sie sie ausführen , den gleichen Code haben wollen, gehen Sie bitte: void myOnCreate() { ... } void onCreate(){myOnCreate();} void onRestart() {myOnCreate();}statt.
18446744073709551615
1
@Fraggles Weil es Ihren Code nicht mehr wartbar macht . Im allgemeinen ist es richtig , wenn die Funktion onRestart () ruft super.onRestart () . Wenn Sie jedoch onCreate () von onRestart () aus aufrufen , wird diese völlig vernünftige Annahme für Ihr Projekt falsch. Beispielsweise ist es im Allgemeinen auch richtig, wenn Sie feststellen, dass Sie in allen Aktivitäten einige Funktionen benötigen, Ihre Klasse ActivityWithSomething zu definieren und die Änderung Activity zu erweitern, um ActivityWithSomething für alle Aktivitäten im Projekt zu erweitern.
18446744073709551615