Come posso tornare correttamente a un'attività genitore?


179

Ho 2 attività (A e B) nella mia applicazione Android e utilizzo un intento per passare dall'attività A all'attività B. L'utilizzo di parent_activity è abilitato:

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

Uso anche un tema che fornisce un pulsante SU.

Quindi, dopo aver chiamato l'attività BI, è possibile utilizzare il pulsante SU per tornare all'attività A. Il problema è che l'applicazione sembra richiamare nuovamente la funzione onCreate () dell'attività A e questo non è il comportamento di cui ho bisogno. Ho bisogno che l'attività A assomigli allo stesso modo di prima che chiamassi attività B.

C'è un modo per raggiungere questo obiettivo?

Grazie in anticipo

MODIFICARE:

Non ho scritto alcun codice per iniziare l'attività B dall'attività A. Penso che sia generato automaticamente da eclipse.

La classe B assomiglia a:

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

Pubblica il tuo codice per iniziare l'attività A da B ..
user370305

Se ti capisco bene, puoi usare startActivityForResult () e restituire un resultCode o qualcosa del genere.
Legge Gimenez,

Aggiorna la risposta corretta con tag! La risposta CORRETTA viene da LorenzCK - non dall'utente ......! Contrassegnare questo come corretto è fuorviante e fa sì che un numero ancora maggiore di programmatori fraintenda la navigazione invece della navigazione posteriore!
Zordid,

Accidenti, così tante risposte sbagliate qui, potresti per favore aiutarmi a ripulire questo ...?
Zordid,

@ashiaka - La risposta corretta secondo la progettazione del tuo codice è stata aggiornata.
user370305,

Risposte:


334

Hai dichiarato l'attività A con lo standard launchModenel manifest Android. Secondo la documentazione , ciò significa quanto segue:

Il sistema crea sempre una nuova istanza dell'attività nell'attività di destinazione e indirizza l'intento ad essa.

Pertanto, il sistema è costretto a ricreare l'attività A (ovvero la chiamata onCreate) anche se lo stack di attività viene gestito correttamente.

Per risolvere questo problema è necessario modificare il manifest, aggiungendo il seguente attributo alla dichiarazione di attività A:

android:launchMode="singleTop"

Nota: la chiamata finish()(come suggerito come soluzione precedente) funziona solo quando si è completamente sicuri che l'istanza dell'attività B che si sta terminando vada sopra un'istanza dell'attività A. In flussi di lavoro più complessi (ad esempio, l'avvio dell'attività B da una notifica) questo potrebbe non essere il caso e devi avviare correttamente l'attività A da B.


11
Ecco la spiegazione dei documenti Android, Le modalità "standard" e "singleTop" differiscono l'una dall'altra per un solo aspetto: ogni volta che c'è un nuovo intento per un'attività "standard", viene creata una nuova istanza della classe per rispondere a quell'intento. Ogni istanza gestisce un unico intento. Allo stesso modo, è possibile creare una nuova istanza di un'attività "singleTop" per gestire un nuovo intento. Tuttavia, se l'attività di destinazione ha già un'istanza esistente dell'attività nella parte superiore del suo stack, quell'istanza riceverà il nuovo intento (in una chiamata onNewIntent ()); non viene creata una nuova istanza.
kpsfoo,

Si noti che secondo la documentazione navigateUpFromSameTask(...) dovrebbe essere aggiunto FLAG_ACTIVITY_CLEAR_TOPa upIntent(tramite il navigateUpTo(...)quale dovrebbe risultare lo stesso comportamento (secondo questa guida ), ma la bandiera non è mai impostata - e quindi questa risposta ha senso
Anigif

82

Risposta aggiornata: Up Navigation Design

Devi dichiarare quale attività è il genitore appropriato per ogni attività. Ciò consente al sistema di facilitare i modelli di navigazione come Su perché il sistema può determinare l'attività padre logica dal file manifest.

Quindi per questo devi dichiarare la tua attività principale nel tag Attività con attributo

android:parentActivityName

Piace,

<!-- 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>

Con l'attività genitore dichiarata in questo modo, puoi navigare fino al genitore appropriato come di seguito,

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

Quindi quando si chiama NavUtils.navigateUpFromSameTask(this);questo metodo, termina l'attività corrente e avvia (o riprende) l'attività padre appropriata. Se l'attività principale di destinazione si trova nello stack posteriore dell'attività, viene anticipata come definito da FLAG_ACTIVITY_CLEAR_TOP.

E per visualizzare il pulsante Su devi dichiarare setDisplayHomeAsUpEnabled():

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

Vecchia risposta: (senza navigazione superiore, navigazione posteriore predefinita)

Succede solo se si avvia nuovamente l'attività A dall'attività B.

Usando startActivity().

Invece di questo dall'attività A, avvia l'attività B usando startActivityForResult()e sovrascrivi l' onActivtyResult()attività A.

Ora nell'attività B basta chiamare finish()il pulsante Su. Quindi ora ti sei diretto alle attività A onActivityResult()senza creare di nuovo l'attività A ..


Non so dove si chiama startActivity () nell'attività B. Ho pubblicato il codice sorgente dell'attività B ...
ashiaka,

18
Invece di NavUtils.navigateUpFromSameTask(this); scrivere la riga di codice finish().
user370305,

4
Sorge la domanda: come mai Google non menziona nulla finish()o startActivityForResult()nella sua documentazione sulla navigazione ( developer.android.com/design/patterns/navigation.html )?
cablato il

sembra una soluzione laboriosa. La risposta di @LorenzCK sembra essere molto meglio.
carmen_munich,

Grazie mille per aver utilizzato NavUtils.navigateUpFromSameTask (questo). Un grande vantaggio! Ho cercato un metodo come questo per sostituire finish () che in alcune circostanze non ritorna all'attività genitore. finish () sta essenzialmente tornando all'attività precedente che non è necessariamente l'attività principale.
Hong

22

Avevo praticamente la stessa configurazione che portava allo stesso comportamento indesiderato. Per me ha funzionato: aggiungendo il seguente attributo a un'attività A nella Manifest.xmlmia app:

android:launchMode="singleTask"

Vedi questo articolo per ulteriori spiegazioni.


1
Dal mio punto di vista, la soluzione corretta al problema. Questo si comporterà come se si chiamasse finish () se l'attività esiste nello stack di attività. In caso contrario, verrà creato e avviato.
Johan

5
Questo non è il modo corretto in quanto creerà una nuova attività inutilmente ogni volta, dovresti invece utilizzare launchMode = "singleTop".
kpsfoo,

19

Sebbene sia una vecchia domanda, ecco un'altra (imho la soluzione più pulita e migliore) poiché tutte le risposte precedenti non hanno funzionato per me da quando ho collegato in profondità l'attività B da un widget .

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 ]

Ma vedi anche: https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android


7

Un modo migliore per raggiungere questo obiettivo è usare due cose: chiama:

NavUtils.navigateUpFromSameTask(this);

Ora, affinché questo funzioni, è necessario che il file manifest indichi che l'attività A ha un'attività padre B. L'attività padre non ha bisogno di nulla. Nella versione 4 e successive otterrai una bella freccia indietro senza alcuno sforzo (questo può essere fatto anche nelle versioni precedenti con un po 'di codice, lo inserirò di seguito) Puoi impostare questi dati nella scheda manifest-> dell'applicazione nella GUI (scorrere fino al nome dell'attività principale e metterlo a mano)

Nodo di supporto:

se desideri supportare la versione precedente alla versione 4, devi includere anche i metadati. fare clic con il tasto destro sull'attività, aggiungere-> metadati, nome = android.support.PARENT_ACTIVITY e valore = your.full.activity.name

per ottenere la bella freccia anche nelle versioni inferiori:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

ti preghiamo di notare che avrai bisogno della libreria di supporto versione 7 per far funzionare tutto questo, ma ne vale la pena!


5

Ciò che ha funzionato per me è stato l'aggiunta di:

    @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();
    }

per TheRelevantActivity.javaora sta funzionando come previsto

e sì, non dimenticare di aggiungere:

getSupportActionbar.setDisplayHomeAsUpEnabled(true);nel onCreate()metodo


4

Ci ho provato android:launchMode="singleTask", ma non ha aiutato. Ha funzionato per me usandoandroid:launchMode="singleInstance"


Aggiunta di android: launchMode = "singleInstance" all'attività dei genitori risolto il problema per me
emir

4

Aggiungendo alla risposta di @ LorenCK, modifica

NavUtils.navigateUpFromSameTask(this);

al codice riportato di seguito se l'attività può essere avviata da un'altra attività e ciò può diventare parte dell'attività avviata da un'altra app

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

Ciò avvierà una nuova attività e avvierà l'attività principale dell'attività che puoi definire in Manifest come sotto della versione SDK minima <= 15

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

O usando parentActivityNamese è> 15


Nota: dichiarare parentActivityNameper SDK> 15 oppure ti darà alcuni crash casuali
Sourabh

3

Ho avuto un problema simile utilizzando Android 5.0 con un nome di attività genitore errato

<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>

Ho rimosso com.example.myfirstapp dal nome dell'attività genitore e ha funzionato correttamente


2

Aggiungi alla tua attività informazioni manifest con attributo

android:launchMode="singleTask"

sta funzionando bene per me


1
Il flusso completo è simile a quello su @Override pubblico booleano onOptionsItemSelected (voce MenuItem) {switch (item.getItemId ()) {case android.R.id.home: NavUtils.navigateUpFromSameTask (this); ritorno vero; } return super.onOptionsItemSelected (oggetto); }
Pravesh Kumar l'

Aggiungi al tuo manifest <attività android: name = ". MainActivity" android: label = "@ string / title_activity_main"> </activity> <attività android: name = ". CreateEventActivity" android: label = "@ string / title_activity_create_event" android : launchMode = "singleTask" android: parentActivityName = ". MainActivity"> <meta-data android: name = "android.support.PARENT_ACTIVITY" android: value = ". MainActivity" /> </activity>
Pravesh Kumar

2

Nella classe Java: -

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

    getSupportActionBar().setTitle("Snapdeal");

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

In 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>

Ti aiuterà


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

come una stampa posteriore


1

prova questo:

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

0

Andare nel mio manifest e aggiungere android:launchMode="singleTop"all'attività ha fatto il trucco per me.

Ciò ha risolto in modo specifico il mio problema perché non volevo che Android creasse una nuova istanza dell'attività precedente dopo aver Uppremuto il pulsante nella barra degli strumenti; volevo invece utilizzare l'istanza esistente dell'attività precedente quando salivo la gerarchia di navigazione.

Riferimento: android: launchMode


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.