Domanda

Nella mia applicazione Android, quando ruoto il dispositivo (fai scorrere fuori la tastiera), my Activity viene riavviato (onCreate è chiamato).Ora, probabilmente è così che dovrebbe essere, ma faccio molta configurazione iniziale in onCreate metodo, quindi ho bisogno di:

  1. Metti tutta la configurazione iniziale in un'altra funzione in modo che non vada persa tutta durante la rotazione del dispositivo o
  2. Fallo così onCreate non viene richiamato di nuovo e il layout viene semplicemente modificato o
  3. Limita l'app solo al ritratto in questo modo onCreate non viene chiamato.
È stato utile?

Soluzione

Utilizzando la classe dell'applicazione

A seconda di cosa stai facendo nella tua inizializzazione, potresti prendere in considerazione la creazione di una nuova classe che si estende Application e spostando il codice di inizializzazione in un file sovrascritto onCreate metodo all'interno di quella classe.

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

IL onCreate nella classe dell'applicazione viene chiamato solo quando viene creata l'intera applicazione, quindi l'attività si riavvia in seguito alle modifiche dell'orientamento o della visibilità della tastiera non la attiverà.

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

NOTA:Dovrai specificare il nome della tua nuova classe Application nel manifest affinché possa essere registrata e utilizzata:

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

Reazione ai cambiamenti di configurazione [AGGIORNAMENTO:questo è deprecato dall'API 13; vedere l'alternativa consigliata]

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

Inizia aggiungendo il android:configChanges nodo 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 versioni successive:

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

Quindi all'interno dell'attività sovrascrivi il file onConfigurationChanged metodo e chiamata setContentView per forzare la riesecuzione del layout della GUI nel nuovo orientamento.

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

Altri suggerimenti

Aggiornamento per Android 3.2 e versioni successive:

  

Attenzione : a partire da Android 3.2 (livello API 13), il " dimensioni 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 valore "screenSize" oltre al valore "orientation". 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 superiore).

Invece di provare a fermare il onCreate() di essere sparato del tutto, forse prova a controllare che Bundle savedInstanceState venga passato nell'evento per vedere se è nullo o meno.

Ad esempio, se ho una logica che dovrebbe essere eseguita quando Activity è veramente creata, non ad ogni cambio di orientamento, eseguo quella logica solo in <=> solo se <=> è null.

Altrimenti, voglio ancora che il layout venga ridisegnato correttamente 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.

quello che ho fatto ...

nel manifest, nella sezione attività, aggiunto:

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

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

android:configChanges

al tuo manifest e quindi alle modifiche che desideri gestire. Quindi, per l'orientamento, dovresti usare:

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"

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

Spero che questo aiuti.

Ho appena scoperto questa tradizione:

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

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

che ha il vantaggio extra che funziona sempre.

Il bonus è che omettere keyboardHidden può sembrare logico, ma causa errori nell'emulatore (almeno per Android 2.1): specificando solo orientation si farà chiamare sia l'emulatore OnCreate che <=> a volte, e solo <=> altre 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.

Potresti anche prendere in considerazione l'uso del modo della piattaforma Android di conservare i dati attraverso i cambiamenti di orientamento: onRetainNonConfigurationInstance () e getLastNonConfigurationInstance () .

Ciò ti consente di conservare i dati attraverso le modifiche alla configurazione, come informazioni che potresti aver ottenuto da un recupero del server o qualcos'altro che è stato calcolato in onCreate o da allora, consentendo allo stesso tempo ad Android di ridimensionare il tuo Activity utilizzando il 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 suggerisce la maggior parte delle soluzioni di cui sopra) con la raccomandazione che tutti passano a Frammenti e invece usano < code> setRetainInstance (true) su ogni frammento che desideri conservare.

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); nei costruttori del frammento

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

http://developer.android.com/ di riferimento / android / app / Fragment.html # setRetainInstance (booleano)

Ho appena aggiunto

     android:configChanges="keyboard|keyboardHidden|orientation"

nel file manifest e non ha aggiunto nessun metodo onConfigurationChanged nella mia attività.

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

Il metodo onCreate viene ancora chiamato anche quando cambi l'orientamento di Android. Quindi spostare tutte le funzionalità pesanti su questo metodo non ti aiuterà

È 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 tuo requisito

Inserisci il codice di seguito nel tag < activity > in Manifest.xml :

android:configChanges="screenLayout|screenSize|orientation"
 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 gli dice " non chiamare onCreate () " ;?

Inoltre, I documenti di Google dicono di evitare di usare android: configChanges (tranne che come ultima risorsa) .... Ma poi i metodi alternativi che suggeriscono a tutti DO usano android: configChanges .

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

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

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

Esistono diversi modi per farlo:

Salva stato attività

Puoi 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 bundle per 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 è quella di 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
    }
}

Limita 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 a livello di codice nella tua attività:

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

Il modo in cui ho scoperto di farlo è usare gli eventi onRestoreInstanceState e onSaveInstanceState per salvare qualcosa nel Bundle (anche se tu non è necessario salvare alcuna variabile, basta inserire qualcosa in modo che Bundle non sia vuoto). Quindi, sul metodo onCreate , controlla se Bundle è vuoto e, se lo è, quindi esegui l'inizializzazione, in caso contrario, quindi eseguilo.

Anche se non è " il modo Android " Ho ottenuto ottimi risultati gestendo personalmente i cambiamenti di orientamento e riposizionando semplicemente i widget in una prospettiva per tenere conto dell'orientamento modificato. 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 modello, ma anche lo stato di visualizzazione, può essere preservato in questo modo.

RelativeLayout a 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 metodo onConfigurationChanged () , passi quello appropriato a una chiamata setLayoutParams () su ogni bambino. Se uno stesso controllo figlio deve essere riorientato internamente , basta 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.

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à.     Fai riferimento a 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"/>

Nota: inserisco 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)

devi usare il metodo onSavedInstanceState per archiviare tutto il valore nel suo parametro è che è bundle

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

e usa

@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

Nella sezione attività del manifest , aggiungi:

android:configChanges="keyboardHidden|orientation"

Aggiungi questa riga in manifest: android:configChanges="orientation|screenSize"

Le persone dicono 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.

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

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>

MainActivity:

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 .

Utilizza l'ascoltatore orientamento 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);
    }
}

Inserisci questo codice sotto nel tuo Activity in Android Manifest .

android:configChanges="orientation"

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

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

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

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

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 in modo lungo tutto il 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 / architettura / viewmodel

Puoi bloccare l'orientamento corrente dello schermo usando questo codice ...

int currentOrientation =context.getResources().getConfiguration().orientation;
        if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
            ((Activity) context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } else {
            ((Activity) context). setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top