studio Aktivität Neustart bei Rotation Android




android studio rotate screen (20)

Wenn ich in meiner Android-Anwendung das Gerät onCreate (die Tastatur onCreate ), wird meine Activity neu gestartet ( onCreate wird aufgerufen). Nun, das ist wahrscheinlich so, wie es sein sollte, aber ich mache eine Menge von onCreate in der onCreate Methode, also brauche ich entweder:

  1. Legen Sie die Ersteinrichtung in eine andere Funktion, so dass bei der Gerätedrehung nicht alles verloren geht oder
  2. Mach es so onCreate wird nicht noch einmal aufgerufen und das Layout passt gerade an oder
  3. Begrenzen Sie die App auf nur Hochformat, damit onCreate nicht aufgerufen wird.

https://code.i-harness.com


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

Welcher Teil des Manifests sagt, dass " onCreate() " nicht aufgerufen wird?

Auch die Google-Dokumente sagen, dass die Verwendung von android:configChanges (außer als letztes Mittel) zu vermeiden ist .... Aber dann verwenden die alternativen Methoden, die sie vorschlagen, alle android:configChanges .

Es ist meine Erfahrung, dass der Emulator onCreate() bei Rotation aufruft.
Aber die 1-2 Geräte, auf denen ich den gleichen Code laufen lasse ... nicht. (Nicht sicher, warum es einen Unterschied geben würde.)


Änderungen, die im Android-Manifest vorgenommen werden müssen, sind:

android:configChanges="keyboardHidden|orientation" 

Innerhalb der Aktivität müssen folgende Ergänzungen vorgenommen werden:

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

Dazu gibt es mehrere Möglichkeiten:

Aktivitätsstatus speichern

Sie können den Aktivitätsstatus 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);
}

Verwenden Sie dann das bundle , um den Status wiederherzustellen.

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

Orientierungsänderungen selbständig handhaben

Eine weitere Alternative besteht darin, die Orientierungsänderungen selbst zu handhaben. Dies wird jedoch nicht als gute Praxis angesehen.

Fügen Sie dies Ihrer Manifestdatei hinzu.

android:configChanges="keyboardHidden|orientation"

für Android 3.2 und höher:

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

Rotation beschränken

Sie können Ihre Aktivität auch auf Hoch- oder Querformat beschränken, um eine Rotation zu vermeiden.

Fügen Sie dies zum Aktivitäts-Tag in Ihrer Manifest-Datei hinzu:

        android:screenOrientation="portrait"

Oder implementieren Sie dies programmatisch in Ihrer Aktivität:

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


Die Methode, die ich gefunden habe, ist, die onRestoreInstanceState und onSaveInstanceState Ereignisse zu verwenden, um etwas im Bundle zu speichern (auch wenn Sie keine gespeicherten Variablen benötigen, legen Sie einfach etwas hinein, damit das Bundle nicht leer ist). Überprüfen Sie dann bei der onCreate Methode, ob das Bundle leer ist, und wenn dies der onCreate ist, führen Sie die Initialisierung durch, wenn nicht, dann tun Sie es.


Es ist sehr einfach, nur die folgenden Schritte auszuführen:

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

Das funktioniert für mich:

Hinweis: Die Ausrichtung hängt von Ihrer Anforderung ab


Fügen Sie diese Zeile android: configChanges = "orientation | screenSize" in Manifest hinzu


Fügen Sie diese Zeile zu Ihrem Manifest hinzu:

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

und dieses Snippet zur Aktivität: -

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


Ich habe gerade diese Überlieferung entdeckt:

Um die Aktivität durch eine Orientierungsänderung am Leben zu erhalten und sie über onConfigurationChanged , onConfigurationChanged die Dokumentation und das obige Codebeispiel onConfigurationChanged in der Manifest-Datei vor:

android:configChanges="keyboardHidden|orientation"

Das hat den zusätzlichen Vorteil, dass es immer funktioniert.

Die Bonusüberlieferung ist, dass das Auslassen der keyboardHidden logisch erscheinen mag, aber es verursacht Fehler im Emulator (zumindest für Android 2.1): OnCreate nur die orientation wird, ruft der Emulator manchmal OnCreate und onConfigurationChanged und nur OnCreate andere Male auf.

Ich habe den Fehler auf einem Gerät nicht gesehen, aber ich habe gehört, dass der Emulator für andere versagt hat. Es lohnt sich also, zu dokumentieren.


Leute sagen, dass du verwenden solltest

android:configChanges="keyboardHidden|orientation"

Aber die beste und professionellste Art, mit der Rotation in Android umzugehen, ist die Loader-Klasse. Es ist keine berühmte Klasse (ich weiß nicht warum), aber es ist viel besser als die AsyncTask. Ich habe es benutzt, um die Popular-Movies-Part-1-Aufgabe aus dem Android-Nano-Studiengang zu vervollständigen.

Beliebte Filme Teil 1

Natürlich könnten Sie die Werte oder die Ansichten mit onSaveInstanceState speichern und sie mit onRestoreInstanceState lesen. Es liegt wirklich an dir.


Nach einer Weile der Versuch und Irrtum fand ich eine Lösung, die in den meisten Situationen meine Bedürfnisse erfüllt. Hier ist der Code:

Manifestkonfiguration:

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

Hauptaktivität:

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

}

Und Beispielfragment:

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

}

Kann auf github .


Platziere diesen Code in deiner Activity in Android Manifest .

android:configChanges="orientation"

Dadurch wird Ihre Aktivität nicht neu gestartet, wenn Sie die Ausrichtung ändern.


Sie können auch die Art und Weise des onRetainNonConfigurationInstance() von Daten der Android-Plattform über Orientierungsänderungen hinweg in onRetainNonConfigurationInstance() : onRetainNonConfigurationInstance() und getLastNonConfigurationInstance() .

Auf diese Weise können Sie Daten über Konfigurationsänderungen hinweg beibehalten, z. B. Informationen, die Sie möglicherweise von einem Server-Abruf oder einem anderen in onCreate oder seither berechneten onCreate , während Android Ihre Activity jetzt mithilfe der XML-Datei neu onCreate in Benutzung.

Siehe here oder hier .

Es sollte beachtet werden, dass diese Methoden nun veraltet sind (obwohl sie immer noch flexibler sind als die Orientierungsänderung selbst, wie die meisten der obigen Lösungen nahelegen) mit der Empfehlung, dass jeder zu Fragments und stattdessen setRetainInstance(true) für jedes Fragment du behalten möchtest .


Update für Android 3.2 und höher:

Achtung : Ab Android 3.2 (API Level 13) ändert sich auch die "Bildschirmgröße", wenn das Gerät zwischen Hoch- und Querformat wechselt. Wenn Sie daher bei der Entwicklung für die API-Stufe 13 oder höher (wie von den Attributen minSdkVersion und targetSdkVersion deklariert) Laufzeit-Neustarts aufgrund von Orientierungsänderungen verhindern möchten, müssen Sie den Wert "screenSize" zusätzlich zum Wert für "orientation" "screenSize" . Das heißt, Sie müssen android:configChanges="orientation|screenSize" . Wenn Ihre Anwendung jedoch auf die API-Stufe 12 oder niedriger abzielt, verarbeitet Ihre Aktivität diese Konfigurationsänderung immer selbst (diese Konfigurationsänderung startet Ihre Aktivität nicht neu, selbst wenn sie auf einem Gerät mit Android 3.2 oder höher ausgeführt wird).


Verwenden Sie den orientation , um verschiedene Aufgaben mit unterschiedlicher Ausrichtung auszuführen.

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

Was ich getan habe...

im Manifest zum Aktivitätsabschnitt hinzugefügt:

android:configChanges="keyboardHidden|orientation"

im Code für die Aktivität implementiert:

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

AndroidManifest.xml die Bildschirmausrichtung ( AndroidManifest.xml oder Hochformat) in AndroidManifest.xml

android:screenOrientation="portrait" oder android:screenOrientation="landscape"

dafür wird Ihre onResume() Methode nicht aufgerufen.


Verwenden der Anwendungsklasse

Je nachdem, was Sie bei der Initialisierung tun, können Sie eine neue Klasse erstellen, die Application und den Initialisierungscode in eine überschriebene onCreate Methode innerhalb dieser Klasse verschiebt.

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

Das onCreate in der Anwendungsklasse wird nur aufgerufen, wenn die gesamte Anwendung erstellt wurde. Die Aktivität wird also neu onCreate wenn Änderungen an der Tastatursichtbarkeit nicht ausgelöst werden.

Es empfiehlt sich, die Instanz dieser Klasse als Singleton verfügbar zu machen und die Anwendungsvariablen, die Sie initialisieren, mithilfe von Getter und Setter freizulegen.

HINWEIS: Sie müssen den Namen Ihrer neuen Application-Klasse im Manifest angeben, damit sie registriert und verwendet werden kann:

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

Reagieren auf Konfigurationsänderungen [UPDATE: Dies ist veraltet seit API 13; siehe die empfohlene Alternative ]

Als weitere Alternative können Sie Ihre Anwendung auf Ereignisse aufmerksam machen lassen, die einen Neustart verursachen - z. B. Ausrichtung und Änderungen der Tastatursichtbarkeit - und diese in Ihrer Aktivität behandeln.

Beginnen Sie, indem Sie den Knoten android:configChanges zum Manifestknoten Ihrer Aktivität hinzufügen

android:configChanges="keyboardHidden|orientation"

oder für Android 3.2 (API Level 13) und neuer :

android:configChanges="keyboardHidden|orientation|screenSize"

onConfigurationChanged dann innerhalb der Aktivität die onConfigurationChanged Methode und rufen Sie setContentView auf, um zu erzwingen, dass das GUI-Layout in der neuen Ausrichtung erneut ausgeführt wird.

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

Mit diesem Code können Sie die aktuelle Ausrichtung des Bildschirms festlegen ...

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






android-activity