Riavvio dell'attività su Android rotazione


1380

Nella mia applicazione Android, quando ruoto il dispositivo (faccio scorrere la tastiera) quindi il mio Activityviene riavviato (onCreate viene chiamato). Ora, questo è probabilmente come dovrebbe essere, ma faccio molte impostazioni iniziali nel onCreatemetodo, quindi ho bisogno di entrambi:

  1. Metti tutte le impostazioni iniziali in un'altra funzione in modo che non siano tutte perse durante la rotazione del dispositivo o
  2. Rendilo così onCreate non venga richiamato di nuovo e il layout si regola o
  3. Limitare l'app a solo ritratto in modo che onCreatenon venga chiamato.

4
In questo post del blog c'è una spiegazione piuttosto completa su come conservare le attività asincrone di lunga durata durante le modifiche alla configurazione delle attività !
Adrian Monk,

3
Questa non è una risposta diretta come hanno già risposto altri, ma ti invito a dare un'occhiata a LogLifeCycle per capire cosa succede nelle tue app Android per quanto riguarda i cicli di vita.
Snicolas,

Risposte:


965

Utilizzando la classe di applicazione

A seconda di ciò che stai facendo nella tua inizializzazione, potresti prendere in considerazione la creazione di una nuova classe che estende Applicatione sposta il tuo codice di inizializzazione in un onCreatemetodo ignorato all'interno di quella classe.

public class MyApplicationClass extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // TODO Put your application initialization code here.
  }
}

L' onCreatenella classe di applicazione si chiama solo quando viene creata l'intera applicazione, quindi il riavvio di attività sull'orientamento o tastiera modifiche di visibilità non attivano esso.

È buona norma esporre l'istanza di questa classe come singleton ed esporre le variabili dell'applicazione che si stanno inizializzando utilizzando getter e setter.

NOTA: è necessario specificare il nome della nuova classe di applicazione nel manifest affinché sia ​​registrata e utilizzata:

<application
    android:name="com.you.yourapp.MyApplicationClass"

Reazione alle modifiche alla configurazione [AGGIORNAMENTO: è obsoleto dall'API 13; vedi l'alternativa consigliata ]

Come ulteriore alternativa, puoi fare in modo che l'applicazione ascolti gli eventi che potrebbero causare un riavvio, come cambiamenti di orientamento e visibilità della tastiera, e gestirli all'interno della tua attività.

Inizia aggiungendo il android:configChangesnodo al nodo manifest della tua attività

 <activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

o per Android 3.2 (livello API 13) e successivi :

<activity android:name=".MyActivity"
      android:configChanges="keyboardHidden|orientation|screenSize"
      android:label="@string/app_name">

Quindi, all'interno dell'Attività, sovrascrivere il onConfigurationChangedmetodo e chiamare setContentViewper forzare il layout della GUI da rifare nel nuovo orientamento.

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.myLayout);
}

17
Non credo che il secondo approccio funzioni. L'ho provato; un'attività con un testo di modifica. Ho scritto del testo lì, ho cambiato orientamento e il testo è sparito / ripristinato.
Ted

231
Speriamo di vedere un metodo onRotate () in futuro. Dover preoccuparsi di cose come questa è - francamente - frustrante.
Kelly Sutton,

84
Nota che la Guida per sviluppatori Android mette in guardia contro l'utilizzo di questo: Nota: l'utilizzo di ( android:configChanges) deve essere evitato e utilizzato solo come ultima risorsa. Leggere Gestione delle modifiche di runtime per ulteriori informazioni su come gestire correttamente un riavvio a causa di una modifica della configurazione. Invece, per mantenere i dati tra gli eventi di rotazione, sembrano preferire usare il onSaveInstanceState Bundle; o come @ Jon-O menziona , onRetainNonConfigurationInstance.
Jeffro,

19
Questa è una cattiva soluzione, perché reagisce solo alle modifiche di configurazione attualmente note . Con le versioni più recenti di Android, possono verificarsi altre modifiche alla configurazione che questo codice non rileva (poiché deve elencare tutte le modifiche di configurazione nel file manifest). La soluzione di salvare lo stato con onRetainNonConfigurationChangesè più tollerante ai guasti e diretta.
Bananeweizen,

16
Penso che dovresti aggiungere questo aggiornamento 3.2 alla tua risposta, è abbastanza importante (ho appena affrontato quel problema) e potrebbe essere trascurato.
bigstones,

185

Aggiornamento per Android 3.2 e versioni successive:

Attenzione : a partire da Android 3.2 (livello API 13), la "dimensione dello schermo" cambia anche quando il dispositivo passa dall'orientamento verticale a quello orizzontale. Pertanto, se si desidera impedire il riavvio del runtime a causa della modifica dell'orientamento durante lo sviluppo per livello API 13 o superiore (come dichiarato dagli attributi minSdkVersion e targetSdkVersion), è necessario includere il "screenSize"valore oltre al "orientation"valore. Cioè, devi dichiarare android:configChanges="orientation|screenSize". Tuttavia, se l'applicazione ha come target API livello 12 o inferiore, la tua attività gestisce sempre questa modifica della configurazione stessa (questa modifica della configurazione non riavvia la tua attività, anche quando è in esecuzione su un dispositivo Android 3.2 o versione successiva).


1
Grazie per quel chiarimento, poiché un commento sopra su questo mi ha quasi mandato a guardarlo. Attualmente sto prendendo di mira l'API 8 e il mio codice non ha screenSize su configChanges e posso confermare che funziona bene (senza riorientamento) sul dispositivo che ho che esegue ICS.
Carl

Grazie per averlo sottolineato, avevo solo Android: configChanges = set "orientamento | screenSize" e il cambio di orientamento stava ricreando la mia attività, e per la mia vita non sono riuscito a capire perché!
Christopher Perry,

5
Aggiunta di android: configChanges dovrebbe essere usato solo come ultima risorsa . Prendi in considerazione l'utilizzo Fragmentse setRetainInstanceinvece.
Simon Forsberg,

Il punto chiave è screenSizeper Android 3.2 e versioni successive, che ha risolto il mio problema, grazie!
fantouch

127

Invece di provare a fermare il onCreate()licenziamento del tutto, forse prova a controllareBundle savedInstanceState passaggio nell'evento per vedere se è nullo o no.

Ad esempio, se ho una logica che dovrebbe essere eseguita quando Activityviene veramente creata, non ad ogni cambio di orientamento, eseguo quella logica onCreate()solo se ilsavedInstanceState è nulla.

Altrimenti, voglio ancora ridisegnare correttamente il layout per l'orientamento.

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

non sono sicuro che questa sia la risposta definitiva, ma funziona per me.


6
e dove stai effettivamente salvando lo stato?
Ewok

5
questo sembra funzionare per me e sembra di gran lunga il metodo più semplice. noto che hai ottenuto solo 4 aumenti per questo (5 compresi i miei) contro 373 per l'idea di sottoclasse dell'applicazione, che per me sembra molto più complicata. c'è qualche svantaggio di questo metodo?
steveh,

4
Questa soluzione ha funzionato alla grande per me. ho potuto Intent serverintent = new Intent(MainActivity.this, MessageListener.class);e startService(serverintent);per creare un serverSocket = new ServerSocket(0xcff2);e Socket client = serverSocket.accept();con un BufferedReader(new InputStreamReader(client.getInputStream()));e potrebbe ruotare il mio Android e mantenere la connessione client / server attivo, hanno ancora la rotazione GUI. Secondo il manuale, saveInstanceState viene inizializzato quando viene interrotta l'ultima attività.
Fred F,

3
Non capisco, qual è il trucco? Funziona alla grande e con una complessità molto inferiore rispetto a qualsiasi altra soluzione.
RTF

3
Questo è il modo corretto di farlo su Android. Gli altri modi per catturare fondamentalmente una rotazione con configChanges e tutto ciò che è ingombrante, complesso e non necessario.
LukeWaggoner,

99

cosa ho fatto...

nel manifest, nella sezione attività, sono stati aggiunti:

android:configChanges="keyboardHidden|orientation"

nel codice per l'attività, implementato:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}

3
per chiarire: con la mia implementazione ora puoi avere l'inizializzazione variabile in onCreate () e onConfigurationChanged () saranno semplicemente chiamati per la rotazione dello schermo. Le tue variabili sono ora isolate dalle rotazioni dello schermo ;-) bello ed ez
Someone Somewhere

2
Ho fatto tutto come descritto qui, ma ottengo NullPointerException quando provo a premere un pulsante dopo il cambio di orientamento. Cosa potrebbe esserci di sbagliato?
Finnboy11,

5
tieni presente che la mia risposta è come 3 anni e Android continua a evolversi ... Simon - hai un link al codice di esempio? Questo è ciò di cui le persone hanno bisogno.
Qualcuno da qualche parte

3
Quando si avverte contro Android: configChanges, @ SimonAndréForsberg in realtà sta solo parafrasando i documenti Android . La gestione delle modifiche di runtime contiene informazioni più dettagliate sulle alternative (incluso il codice di esempio).
Leif Arne Storset,

67

Quello che descrivi è il comportamento predefinito. Devi rilevare e gestire questi eventi tu stesso aggiungendo:

android:configChanges

al tuo manifest e quindi ai cambiamenti che vuoi gestire. Quindi per l'orientamento, useresti:

android:configChanges="orientation"

e per l'apertura o la chiusura della tastiera dovresti usare:

android:configChanges="keyboardHidden"

Se vuoi gestirli entrambi puoi semplicemente separarli con il comando pipe come:

android:configChanges="keyboardHidden|orientation"

Ciò attiverà il metodo onConfigurationChanged in qualunque attività tu chiami. Se si ignora il metodo, è possibile passare i nuovi valori.

Spero che sia di aiuto.


2
@GregD Lo so, motivo per cui ora è un buon momento per aggiornarlo per riflettere la situazione di oggi. Dato il numero di voti espressi da questa domanda, essa viene ancora citata da altre domande sulla SO.
Simon Forsberg,

48

Ho appena scoperto questa tradizione:

Per mantenere attiva l'attività attraverso una modifica dell'orientamento e gestirla onConfigurationChanged, la documentazione e l'esempio di codice sopra suggeriscono questo nel file manifest:

<activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

che ha il vantaggio extra che funziona sempre.

La tradizione bonus è che omettendo la keyboardHiddenpuò sembrare logico, ma provoca fallimenti nell'emulatore (per Android 2.1 almeno): specificando solo orientationrenderà la chiamata emulatore sia OnCreatee onConfigurationChangedvolte, e solo OnCreatealtre volte.

Non ho visto l'errore su un dispositivo, ma ho sentito che l'emulatore non funziona per gli altri. Quindi vale la pena documentare.


14
Attenzione: a partire da Android 3.2 (livello API 13), la "dimensione dello schermo" cambia anche quando il dispositivo passa dall'orientamento verticale a quello orizzontale. Pertanto, se si desidera impedire il riavvio del runtime a causa della modifica dell'orientamento durante lo sviluppo per il livello API 13 o superiore: android: configChanges = "orientamento | keyboardHidden | screenSize"
Geltrude

Sì, l'emulatore fa schifo alla grande. Non puoi fare affidamento su di esso per segnalare accuratamente le modifiche alla configurazione.
IgorGanapolsky,

Aggiunta di android: configChanges dovrebbe essere usato solo come ultima risorsa . Prendi in considerazione l'utilizzo Fragmentse setRetainInstanceinvece.
Simon Forsberg,

38

Potresti anche considerare di utilizzare il modo della piattaforma Android di conservare i dati attraverso i cambiamenti di orientamento: onRetainNonConfigurationInstance()egetLastNonConfigurationInstance() .

Ciò ti consente di conservare i dati attraverso le modifiche alla configurazione, come le informazioni che potresti aver ottenuto da un recupero del server o qualcos'altro che è stato calcolato in onCreateo da allora, consentendo anche ad Android di ridimensionare il tuoActivity utilizzo del file xml per l'orientamento ora in uso .

Vedi qui o qui .

Va notato che questi metodi sono ora deprecati (anche se ancora più flessibili della gestione dell'orientamento cambiano te stesso come la maggior parte delle soluzioni di cui sopra suggeriscono) con la raccomandazione che tutti passano Fragmentse invece utilizzano setRetainInstance(true)su ciascuno che Fragmentsi desidera conservare.


3
Penso davvero che Frammenti e setRetainInstance siano il modo migliore (e consigliato da Google) per farlo, +1 per te e -1 per tutti gli altri. Aggiunta di android: configChanges dovrebbe essere usato solo come ultima risorsa
Simon Forsberg

32

L'approccio è utile ma è incompleto quando si usano i frammenti.

I frammenti di solito vengono ricreati al cambio di configurazione. Se non desideri che ciò accada, utilizza

setRetainInstance(true); nel costruttore (i) del frammento

Ciò causerà la conservazione dei frammenti durante la modifica della configurazione.

http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)


7
Concordato. Con l'ultima API di Android, sembra che i frammenti siano il modo corretto di gestirlo. Non l'ho ancora provato da solo, ma da quello che ho raccolto leggendo questa pagina , fondamentalmente sposti il ​​99% di ciò che hai usato per implementare in un'attività in una sottoclasse di un frammento, quindi aggiungi quel frammento all'attività. L'attività verrà comunque distrutta e ricreata con la rotazione dello schermo, ma puoi specificamente dire ad Android di non distruggere il frammento usando il setRetainInstance()metodo @Abdo menzionato.
brianmearns,

25

Ho appena aggiunto

     android:configChanges="keyboard|keyboardHidden|orientation"

nel file manifest e non ha aggiunto alcun onConfigurationChangedmetodo nella mia attività.

Quindi ogni volta che la tastiera scorre o non succede nulla .


aggiunto a <application ...android:configChanges="keyboard|keyboardHidden|orientation">e sta funzionando. Le mie impostazioni in build.gradle:minSdkVersion 15, compileSdkVersion 23, buildToolsVersion "23.0.2"
Junior Mayhé,

19

Il onCreatemetodo viene ancora chiamato anche quando si cambia orientationAndroid. Quindi spostare tutte le funzionalità pesanti su questo metodo non ti aiuterà


18

Inserisci il codice sottostante all'interno del <activity>tag in Manifest.xml:

android:configChanges="screenLayout|screenSize|orientation"

17
 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 android:configChanges)

Quale parte del manifest dice "non chiamare onCreate()"?

Inoltre, documenti di Google dicono di evitare l'uso android:configChanges(se non come ultima risorsa) .... Ma poi i metodi alternativi che suggeriscono tutti DO uso android:configChanges.

È stata la mia esperienza che l'emulatore chiama SEMPRE onCreate()alla rotazione.
Ma i dispositivi 1-2 su cui eseguo lo stesso codice su ... non lo fanno. (Non so perché ci sarebbe qualche differenza.)


16

È molto semplice, basta fare i seguenti passi:

<activity
    android:name=".Test"
    android:configChanges="orientation|screenSize"
    android:screenOrientation="landscape" >
</activity>

Questo funziona per me:

Nota: l' orientamento dipende dal requisito


15

Le modifiche da apportare nel manifest Android sono:

android:configChanges="keyboardHidden|orientation" 

Le aggiunte da effettuare all'interno dell'attività sono:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

15

Aggiungi questa riga al tuo manifest: -

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

e questo frammento dell'attività: -

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

14

Esistono diversi modi per farlo:

Salva stato attività

È possibile salvare lo stato dell'attività in onSaveInstanceState.

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example : outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

e quindi utilizzare il bundleper ripristinare lo stato.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

Gestisci i cambiamenti di orientamento da solo

Un'altra alternativa è gestire i cambiamenti di orientamento da soli. Ma questa non è considerata una buona pratica.

Aggiungi questo al tuo file manifest.

android:configChanges="keyboardHidden|orientation"

per Android 3.2 e versioni successive:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portarit mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

Limitare la rotazione

Puoi anche limitare la tua attività alla modalità verticale o orizzontale per evitare la rotazione.

Aggiungi questo al tag attività nel tuo file manifest:

        android:screenOrientation="portrait"

O implementalo programmaticamente nella tua attività:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

11

Il modo che ho trovato per farlo è utilizzare le onRestoreInstanceStatee gli onSaveInstanceStateeventi per salvare qualcosa nel Bundle(anche se non avete bisogno di tutte le variabili memorizzate, basta mettere qualcosa in là in modo che il Bundlenon è vuoto). Quindi, sul onCreatemetodo, controlla se Bundleè vuoto e se lo è, quindi esegui l'inizializzazione, in caso contrario, quindi eseguilo.


11

Anche se non è "il modo Android", ho ottenuto ottimi risultati gestendo me stesso i cambiamenti di orientamento e semplicemente riposizionando i widget in vista per tenere conto dell'orientamento alterato. Questo è più veloce di qualsiasi altro approccio, perché le tue viste non devono essere salvate e ripristinate. Offre inoltre un'esperienza più fluida all'utente, poiché i widget riposizionati sono esattamente gli stessi widget, appena spostati e / o ridimensionati. Non solo lo stato del modello, ma anche lo stato di visualizzazione, può essere preservato in questo modo.

RelativeLayouta volte può essere una buona scelta per una vista che deve riorientarsi di volta in volta. È sufficiente fornire una serie di parametri di layout verticale e una serie di parametri di layout paesaggistici, con diverse regole di posizionamento relative su ciascuno, per ciascun widget figlio. Quindi, nel tuo onConfigurationChanged()metodo, passi quello appropriato a una setLayoutParams()chiamata su ogni bambino. Se uno stesso controllo figlio deve essere riorientato internamente , è sufficiente chiamare un metodo su quel figlio per eseguire il riorientamento. Quel bambino chiama allo stesso modo metodi su uno qualsiasi dei suoi controlli figlio che necessitano di riorientamento interno e così via.


Mi piacerebbe vedere qualche codice di esempio di questo, sembra geniale!
Henrique de Sousa,

8

Ogni volta che si ruota lo schermo, l'attività aperta viene terminata e viene richiamato onCreate ().

1 Puoi fare una cosa per salvare lo stato di attività quando lo schermo viene ruotato in modo tale da poter recuperare tutte le cose vecchie quando viene richiamato onCreate () di attività. Fare riferimento questo link

2 Se vuoi impedire il riavvio dell'attività, inserisci le seguenti righe nel tuo file manifest.xml.

  <activity android:name=".Youractivity"
  android:configChanges="orientation|screenSize"/>

7

è necessario utilizzare il metodo onSavedInstanceState per memorizzare tutto il valore nel relativo parametro è bundle

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

e usare

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

per recuperare e impostare il valore per visualizzare gli oggetti, gestirà le rotazioni dello schermo


Ciò richiede il livello API 22.
Mohammad Afrashteh,

6

Nota: invio questa risposta se in futuro qualcuno dovesse affrontare lo stesso problema. Per me la seguente riga non era abbastanza:

android:configChanges="orientation"

Quando ho ruotato lo schermo, il metodo `onConfigurationChanged (Configuration newConfig) non è stato chiamato.

Soluzione: ho anche dovuto aggiungere "screenSize" anche se il problema riguardava l'orientamento. Quindi nel file AndroidManifest.xml, aggiungi questo:

android:configChanges="keyboardHidden|orientation|screenSize"

Quindi implementare il metodo onConfigurationChanged(Configuration newConfig)


5

Nella sezione attività di manifest, aggiungi:

android:configChanges="keyboardHidden|orientation"


4

La gente dice che dovresti usare

android:configChanges="keyboardHidden|orientation"

Ma il modo migliore e più professionale per gestire la rotazione in Android è utilizzare la classe Loader. Non è una classe famosa (non so perché), ma è molto meglio dell'AsyncTask. Per ulteriori informazioni, puoi leggere i tutorial Android disponibili nei corsi Android di Udacity.

Naturalmente, in un altro modo, è possibile memorizzare i valori o le viste con onSaveInstanceState e leggerli con onRestoreInstanceState. Dipende davvero da te.


Sì, aggiungiamo goccioline di codice extra per sembrare "professionali". O che ne pensi di seguire il modo rapido, semplice, vero e provato di farlo con l'attributo configurationChanges.
AndroidDev

3

Dopo un po 'di tentativi ed errori, ho trovato una soluzione adatta alle mie esigenze nella maggior parte delle situazioni. Ecco il codice:

Configurazione manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

Attività principale:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume  " + "");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause  " + "");
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy  " + "");
    }


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

E frammento di esempio:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

Può essere trovato su Github .


3

Utilizzare l' orientationascoltatore per eseguire diverse attività con orientamento diverso.

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}

3

Mettete questo sotto codice nel tuo Activityin Android Manifest.

android:configChanges="orientation"

Questo non riavvierà la tua attività quando cambierai l'orientamento.


2
@Mavamaarten Probabilmente perché, come altri hanno sottolineato, è una cattiva pratica e altre dieci risposte hanno già trattato questo.
MikkoP,

3

Correggi l'orientamento dello schermo (orizzontale o verticale) in AndroidManifest.xml

android:screenOrientation="portrait" o android:screenOrientation="landscape"

per questo il tuo onResume()metodo non viene chiamato.


5
come diavolo riparare qualcosa è una risposta? Perché i nostri dispositivi possono ruotare se blocciamo gli utenti che lo utilizzano?
Reinherd,

3

Uno dei migliori componenti di Android Architechure introdotti da Google soddisferà tutti i requisiti di ViewModel.

È progettato per archiviare e gestire i dati relativi all'interfaccia utente nel modo del ciclo di vita, oltre a consentire ai dati di sopravvivere durante la rotazione dello schermo

class MyViewModel : ViewModel() {

Si prega di fare riferimento a questo: https://developer.android.com/topic/libraries/architecture/viewmodel


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.