Wie kann ich korrekt zu einer übergeordneten Aktivität zurückkehren?

179

Ich habe 2 Aktivitäten (A und B) in meiner Android-Anwendung und ich habe die Absicht, von Aktivität A zu Aktivität B zu gelangen. Die Verwendung von parent_activity ist aktiviert:

 <activity
        android:name=".B"
        android:label="B" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
  </activity>

Ich benutze auch ein Thema, das einen UP-Button bietet.

Nachdem ich Aktivität BI aufgerufen habe, kann ich mit der UP-Taste zur Aktivität A zurückkehren. Das Problem ist, dass die Anwendung die onCreate () -Funktion von Aktivität A erneut aufzurufen scheint und dies nicht das Verhalten ist, das ich benötige. Ich brauche Aktivität A, um so auszusehen, wie sie aussah, bevor ich Aktivität B anrief.

Gibt es einen Weg, dies zu erreichen?

Danke im Voraus

BEARBEITEN:

Ich habe keinen Code geschrieben, um Aktivität B von Aktivität A aus zu starten. Ich denke, er wird durch Eclipse automatisch generiert.

Klasse B sieht aus wie:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpFromSameTask(this);
            return true;
    }
    return super.onOptionsItemSelected(item);
}
Ashiaka
quelle
Geben Sie Ihren
Wenn ich Sie richtig verstehe, können Sie startActivityForResult () verwenden und einen resultCode oder etwas zurückgeben.
Law Gimenez
Bitte aktualisieren Sie Ihre getaggte richtige Antwort! Die RICHTIGE Antwort kommt von LorenzCK - nicht vom Benutzer ......! Dies als richtig zu kennzeichnen ist irreführend und lässt noch mehr Programmierer die Navigation falsch verstehen als die Rückwärtsnavigation!
Zordid
Gee, so viele falsche Antworten hier, könnten Sie bitte beim Aufräumen helfen ...?
Zordid
@ashiaka - Die richtige Antwort gemäß Ihrem Code-Design wurde aktualisiert.
user370305

Antworten:

332

Sie haben Aktivität A mit dem Standard launchModeim Android-Manifest deklariert . Laut Dokumentation bedeutet dies Folgendes:

Das System erstellt immer eine neue Instanz der Aktivität in der Zielaufgabe und leitet die Absicht an diese weiter.

Daher ist das System gezwungen, Aktivität A (dh Aufrufen onCreate) neu zu erstellen, selbst wenn der Taskstapel korrekt behandelt wird.

Um dieses Problem zu beheben, müssen Sie das Manifest ändern und der A-Aktivitätsdeklaration das folgende Attribut hinzufügen:

android:launchMode="singleTop"

Hinweis: Das Aufrufen finish()(wie zuvor als Lösung vorgeschlagen) funktioniert nur, wenn Sie völlig sicher sind , dass die Instanz von Aktivität B, die Sie beenden, über einer Instanz von Aktivität A liegt. In komplexeren Workflows (z. B. Starten von Aktivität B über eine Benachrichtigung) Dies ist möglicherweise nicht der Fall und Sie müssen Aktivität A von B aus korrekt starten.

LorenzCK
quelle
11
Hier ist die Erklärung aus Android-Dokumenten: Die Modi "Standard" und "SingleTop" unterscheiden sich nur in einer Hinsicht: Jedes Mal, wenn eine neue Absicht für eine "Standard" -Aktivität vorliegt, wird eine neue Instanz der Klasse erstellt, auf die reagiert werden soll diese Absicht. Jede Instanz behandelt eine einzelne Absicht. In ähnlicher Weise kann auch eine neue Instanz einer "singleTop" -Aktivität erstellt werden, um eine neue Absicht zu behandeln. Wenn die Zielaufgabe jedoch bereits eine vorhandene Instanz der Aktivität oben auf ihrem Stapel hat, erhält diese Instanz die neue Absicht (in einem Aufruf von onNewIntent ()). Eine neue Instanz wird nicht erstellt.
kpsfoo
Beachten Sie, dass nach der Dokumentation navigateUpFromSameTask(...) sollte das Hinzufügen FLAG_ACTIVITY_CLEAR_TOPzu upIntent(über navigateUpTo(...)dem in gleiche Verhalten (gemäß führen sollte dieses Handbuch ), aber die Fahne ist nicht gesetzt - und damit diese Antwort macht Sinn
Anigif
82

Aktualisierte Antwort: Up Navigation Design

Sie müssen angeben, welche Aktivität für jede Aktivität das entsprechende übergeordnete Element ist. Auf diese Weise kann das System Navigationsmuster wie Up vereinfachen, da das System die logische übergeordnete Aktivität aus der Manifestdatei ermitteln kann.

Dazu müssen Sie Ihre übergeordnete Aktivität im Tag Aktivität mit Attribut deklarieren

android:parentActivityName

Mögen,

<!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.app_name.A" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name=".B"
        android:label="B"
        android:parentActivityName="com.example.app_name.A" >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
    </activity>

Wenn die übergeordnete Aktivität auf diese Weise deklariert wurde, können Sie wie unten beschrieben zu dem entsprechenden übergeordneten Element navigieren.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    // Respond to the action bar's Up/Home button
    case android.R.id.home:
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Wenn Sie NavUtils.navigateUpFromSameTask(this);diese Methode aufrufen , wird die aktuelle Aktivität beendet und die entsprechende übergeordnete Aktivität gestartet (oder fortgesetzt). Befindet sich die übergeordnete Zielaktivität im Backstack der Aufgabe, wird sie wie in definiert durch vorgezogen FLAG_ACTIVITY_CLEAR_TOP.

Und um die Schaltfläche Nach oben anzuzeigen, müssen Sie deklarieren setDisplayHomeAsUpEnabled():

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

Alte Antwort: (Ohne Up-Navigation, Standard-Back-Navigation)

Dies geschieht nur, wenn Sie Aktivität A erneut von Aktivität B aus starten.

Verwenden von startActivity().

Starten Sie stattdessen ab Aktivität A Aktivität B, indem Sie Aktivität A verwenden startActivityForResult()und überschreiben onActivtyResult().

Rufen Sie jetzt in Aktivität B einfach die finish()Schaltfläche Nach oben auf. Nun haben Sie zu Aktivität A gewechselt, onActivityResult()ohne erneut Aktivität A zu erstellen.

user370305
quelle
Ich weiß nicht, wo startActivity () in Aktivität B aufgerufen wird. Ich habe den Quellcode der Aktivität B ...
Ashiaka
18
Anstelle von Codezeile NavUtils.navigateUpFromSameTask(this); schreiben finish().
user370305
4
Es stellt sich die Frage, warum Google nichts über finish()oder startActivityForResult()in seiner Dokumentation zur Navigation ( developer.android.com/design/patterns/navigation.html ) erwähnt.
Wired00
Das klingt nach einer mühsamen Problemumgehung. @ LorenzCK Antwort scheint viel besser zu sein.
carmen_munich
Vielen Dank für die Verwendung von NavUtils.navigateUpFromSameTask (this). Großes Plus! Ich habe nach einer Methode wie dieser gesucht, um finish () zu ersetzen, die unter bestimmten Umständen nicht zur übergeordneten Aktivität zurückkehrt. finish () kehrt im Wesentlichen zur vorherigen Aktivität zurück, die nicht unbedingt die übergeordnete Aktivität ist.
Hong
22

Ich hatte so ziemlich das gleiche Setup, was zu dem gleichen unerwünschten Verhalten führte. Für mich hat dies funktioniert: Hinzufügen des folgenden Attributs zu einer Aktivität A in Manifest.xmlmeiner App:

android:launchMode="singleTask"

Weitere Erklärungen finden Sie in diesem Artikel .

androidnewbie
quelle
1
Aus meiner Sicht die richtige Lösung für das Problem. Dies verhält sich genauso, als hätten Sie finish () aufgerufen, wenn die Aktivität im Aufgabenstapel vorhanden ist. Ist dies nicht der Fall, wird es erstellt und gestartet.
Johan
5
Dies ist nicht der richtige Weg, da jedes Mal unnötig eine neue Aufgabe erstellt wird. Verwenden Sie stattdessen den launchMode = "singleTop".
kpsfoo
19

Obwohl es sich um eine alte Frage handelt, ist hier eine andere (imho die sauberste und beste) Lösung, da alle vorherigen Antworten für mich nicht funktionierten, da ich Aktivität B von einem Widget entfernt habe .

public void navigateUp() {
final Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
    Log.v(logTag, "Recreate back stack");
        TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
  } else {
    NavUtils.navigateUpTo(this, upIntent);
  }
}

[ https://stackoverflow.com/a/31350642/570168 ]

Siehe aber auch: https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android

Tobias
quelle
7

Ein besserer Weg, dies zu erreichen, besteht darin, zwei Dinge zu verwenden: call:

NavUtils.navigateUpFromSameTask(this);

Damit dies funktioniert, muss in Ihrer Manifestdatei angegeben sein, dass Aktivität A eine übergeordnete Aktivität B hat. Die übergeordnete Aktivität benötigt nichts. In Version 4 und höher erhalten Sie ohne zusätzlichen Aufwand einen schönen Rückpfeil (dies kann auch bei niedrigeren Versionen mit ein wenig Code durchgeführt werden, ich werde es unten einfügen). Sie können diese Daten auf der Registerkarte Manifest-> Anwendung festlegen in der GUI (scrollen Sie nach unten zum Namen der übergeordneten Aktivität und geben Sie ihn von Hand ein)

Unterstützungsknoten:

Wenn Sie eine Version unter Version 4 unterstützen möchten, müssen Sie auch Metadaten einschließen. Klicken Sie mit der rechten Maustaste auf die Aktivität, fügen Sie-> Metadaten hinzu, name = android.support.PARENT_ACTIVITY und value = your.full.activity.name

um den schönen Pfeil auch in niedrigeren Versionen zu bekommen:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Bitte beachten Sie, dass Sie die Support-Bibliothek Version 7 benötigen, damit dies alles funktioniert, aber es lohnt sich!

Donald
quelle
5

Was für mich funktionierte, war das Hinzufügen von:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

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

zu TheRelevantActivity.javaund jetzt funktioniert es wie erwartet

und ja, vergiss nicht hinzuzufügen:

getSupportActionbar.setDisplayHomeAsUpEnabled(true);in onCreate()Methode

Hammad Nasir
quelle
4

Ich habe es versucht android:launchMode="singleTask", aber es hat nicht geholfen. Arbeitete für mich mitandroid:launchMode="singleInstance"

Pnemonisch
quelle
Hinzufügen von Android: launchMode = "singleInstance" zur übergeordneten Aktivität gelöst Problem für mich
Emir
4

Ändern Sie die Antwort von @ LorenCK und ändern Sie sie

NavUtils.navigateUpFromSameTask(this);

Klicken Sie auf den folgenden Code, wenn Ihre Aktivität von einer anderen Aktivität aus initiiert werden kann und dies Teil einer Aufgabe werden kann, die von einer anderen App gestartet wurde

Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    TaskStackBuilder.create(this)
            .addNextIntentWithParentStack(upIntent)
            .startActivities();
} else {
    NavUtils.navigateUpTo(this, upIntent);
}

Dadurch wird eine neue Aufgabe gestartet und die übergeordnete Aktivität Ihrer Aktivität gestartet, die Sie im Manifest wie unten in Min SDK Version <= 15 definieren können

<meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app_name.A" />

Oder verwenden, parentActivityNamewenn es> 15 ist

Sourabh
quelle
Hinweis: Deklarieren Sie parentActivityNamefür SDK> 15, sonst kommt es zu zufälligen Abstürzen
Sourabh
3

Ich hatte ein ähnliches Problem mit Android 5.0 mit einem schlechten Namen der Elternaktivität

<activity
        android:name=".DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName=".MainActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>

Ich habe die Datei com.example.myfirstapp aus dem Namen der übergeordneten Aktivität entfernt und sie hat ordnungsgemäß funktioniert

Patrick Bergthold
quelle
2

Fügen Sie Ihrer Aktivität Manifestinformationen mit Attribut hinzu

android:launchMode="singleTask"

arbeitet gut für mich

Pravesh Kumar
quelle
1
Der vollständige Ablauf ist wie folgt: @Override public boolean onOptionsItemSelected (MenuItem-Element) {switch (item.getItemId ()) {case android.R.id.home: NavUtils.navigateUpFromSameTask (this); return true; } return super.onOptionsItemSelected (item); }
Pravesh Kumar
Fügen Sie Ihrem Manifest hinzu <activity android: name = ". MainActivity" android: label = "@ string / title_activity_main"> </ activity> <activity android: name = ". CreateEventActivity" android: label = "@ string / title_activity_create_event" android : launchMode = "singleTask" android: parentActivityName = ". MainActivity"> <Metadaten android: name = "android.support.PARENT_ACTIVITY" android: value = ". MainActivity" /> </ activity>
Pravesh Kumar
2

In der Java-Klasse: -

    toolbar = (Toolbar) findViewById(R.id.apptool_bar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setTitle("Snapdeal");

    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Im Manifest: -

<activity
            android:name=".SubActivity"
            android:label="@string/title_activity_sub"
            android:theme="@style/AppTheme" >
            <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"></meta-data>
    </activity>

Es wird dir helfen

Kasthuri Shravankumar
quelle
1
    @Override
public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
    case android.R.id.home:
        finish();
        return true;
}
return super.onOptionsItemSelected(item);

wie ein Zurück drücken

Dan Alboteanu
quelle
1

Versuche dies:

Intent intent;
@Override
public void onCreate(Bundle savedInstanceState) {
    intent = getIntent();   
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}  

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpTo(this,intent);
            return true;
    }
    return super.onOptionsItemSelected(item);
}
Luis Valadez
quelle
0

In mein Manifest zu gehen und android:launchMode="singleTop"die Aktivität zu erweitern, hat den Trick für mich getan.

Dies löste speziell mein Problem, da ich nicht wollte, dass Android eine neue Instanz der vorherigen Aktivität erstellt, nachdem Upich auf die Schaltfläche in der Symbolleiste geklickt hatte. Stattdessen wollte ich die vorhandene Instanz der vorherigen Aktivität verwenden, als ich die Navigationshierarchie aufstieg.

Referenz: android: launchMode

mumush
quelle