Suche…


Bemerkungen

Referenz: https://guides.codepath.com/android/Handling-Configuration-Changes#references

Aktivitätsstatus speichern und wiederherstellen

Wenn Ihre Aktivität zu stoppen beginnt, ruft das System onSaveInstanceState() damit Ihre Aktivität Zustandsinformationen mit einer Sammlung von Schlüssel-Wert-Paaren speichern kann. Die Standardimplementierung dieser Methode speichert automatisch Informationen zum Status der Ansichtshierarchie der Aktivität, z. B. den Text in einem EditText Widget oder die ListView einer ListView .

Um zusätzliche onSaveInstanceState() für Ihre Aktivität zu speichern, müssen Sie onSaveInstanceState() implementieren und dem Bundle-Objekt Schlüsselwertpaare hinzufügen. Zum Beispiel:

public class MainActivity extends Activity {
    static final String SOME_VALUE = "int_value";
    static final String SOME_OTHER_VALUE = "string_value";

    @Override
    protected void onSaveInstanceState(Bundle savedInstanceState) {
        // Save custom values into the bundle
        savedInstanceState.putInt(SOME_VALUE, someIntValue);
        savedInstanceState.putString(SOME_OTHER_VALUE, someStringValue);
        // Always call the superclass so it can save the view hierarchy state
        super.onSaveInstanceState(savedInstanceState);
    }
}

Das System ruft diese Methode auf, bevor eine Aktivität zerstört wird. Später ruft das System onRestoreInstanceState wo wir den Status aus dem Bundle wiederherstellen können:

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);
    // Restore state members from saved instance
    someIntValue = savedInstanceState.getInt(SOME_VALUE);
    someStringValue = savedInstanceState.getString(SOME_OTHER_VALUE);
}

Der Instanzstatus kann auch in der standardmäßigen Activity # onCreate-Methode wiederhergestellt werden. In onRestoreInstanceState ist dies jedoch onRestoreInstanceState wodurch sichergestellt wird, dass die gesamte Initialisierung abgeschlossen ist und die Unterklassen entscheiden, ob sie die Standardimplementierung verwenden. Lesen Sie diesen Stackoverflow-Beitrag für Details.

Beachten Sie, dass es nicht garantiert ist, dass onSaveInstanceState und onRestoreInstanceState gemeinsam aufgerufen werden. Android ruft onSaveInstanceState() wenn die Möglichkeit besteht, dass die Aktivität zerstört wird. Es gibt jedoch Fälle, in denen onSaveInstanceState aufgerufen wird, die Aktivität jedoch nicht zerstört wird und onRestoreInstanceState daher nicht aufgerufen wird.

Fragmentstatus speichern und wiederherstellen

Fragmente haben auch eine onSaveInstanceState() Methode, die aufgerufen wird, wenn ihr Status gespeichert werden muss:

public class MySimpleFragment extends Fragment {
    private int someStateValue;
    private final String SOME_VALUE_KEY = "someValueToSave";
   
    // Fires when a configuration change occurs and fragment needs to save state
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt(SOME_VALUE_KEY, someStateValue);
        super.onSaveInstanceState(outState);
    }
}

Dann können wir Daten aus diesem gespeicherten Status in onCreateView :

public class MySimpleFragment extends Fragment {
   // ...

   // Inflate the view for the fragment based on layout XML
   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.my_simple_fragment, container, false);
        if (savedInstanceState != null) {
            someStateValue = savedInstanceState.getInt(SOME_VALUE_KEY);
            // Do something with value if needed
        }
        return view;
   }
}

Damit der Fragmentstatus ordnungsgemäß gespeichert werden kann, müssen wir sicherstellen, dass das Fragment bei Konfigurationsänderungen nicht unnötig neu erstellt wird. Dies bedeutet, dass Sie vorhandene Fragmente nicht erneut initialisieren, wenn sie bereits vorhanden sind. Alle Fragmente, die in einer Aktivität initialisiert werden, müssen nach einer Konfigurationsänderung nach einem Tag gesucht werden:

public class ParentActivity extends AppCompatActivity {
    private MySimpleFragment fragmentSimple;
    private final String SIMPLE_FRAGMENT_TAG = "myfragmenttag";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (savedInstanceState != null) { // saved instance state, fragment may exist
           // look up the instance that already exists by tag
           fragmentSimple = (MySimpleFragment)  
              getSupportFragmentManager().findFragmentByTag(SIMPLE_FRAGMENT_TAG);
        } else if (fragmentSimple == null) { 
           // only create fragment if they haven't been instantiated already
           fragmentSimple = new MySimpleFragment();
        }
    }
}

Dies erfordert, dass wir ein Tag für die Suche einschließen, wenn Sie ein Fragment in die Aktivität einer Transaktion einfügen:

public class ParentActivity extends AppCompatActivity {
    private MySimpleFragment fragmentSimple;
    private final String SIMPLE_FRAGMENT_TAG = "myfragmenttag";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ... fragment lookup or instantation from above...
        // Always add a tag to a fragment being inserted into container
        if (!fragmentSimple.isInLayout()) {
            getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.container, fragmentSimple, SIMPLE_FRAGMENT_TAG)
                .commit();
        }
    }
}

Mit diesem einfachen Muster können wir Fragmente ordnungsgemäß wiederverwenden und ihren Status bei Konfigurationsänderungen wiederherstellen.

Fragmente erhalten

In vielen Fällen können Probleme vermieden werden, wenn eine Aktivität neu erstellt wird, indem einfach Fragmente verwendet werden. Wenn sich Ihre Ansichten und Ihr Status in einem Fragment befinden, kann das Fragment leicht beibehalten werden, wenn die Aktivität neu erstellt wird:

public class RetainedFragment extends Fragment {
    // data object we want to retain
    private MyDataObject data;

    // this method is only called once for this fragment
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment when activity is re-initialized
        setRetainInstance(true);
    }

    public void setData(MyDataObject data) {
        this.data = data;
    }

    public MyDataObject getData() {
        return data;
    }
}

Dieser Ansatz verhindert, dass das Fragment während des Aktivitätslebenszyklus zerstört wird. Sie werden stattdessen im Fragment-Manager beibehalten. Weitere Informationen finden Sie in den offiziellen Dokumenten von Android.

Jetzt können Sie anhand des Tags prüfen, ob das Fragment bereits vorhanden ist, bevor Sie ein Fragment erstellen, und das Fragment behält seinen Status bei Konfigurationsänderungen. Weitere Informationen finden Sie im Handbuch Umgang mit Laufzeitänderungen.

Bildschirmausrichtung sperren

Wenn Sie die Änderung der Bildschirmausrichtung eines Bildschirms (Aktivität) Ihrer Android-Anwendung sperren möchten, müssen Sie lediglich die android:screenOrientation einer <activity> im AndroidManifest.xml festlegen :

<activity
    android:name="com.techblogon.screenorientationexample.MainActivity"
    android:screenOrientation="portrait"
    android:label="@string/app_name" >
    <!-- ... -->
</activity>

Nun muss diese Aktivität immer im Hochformat angezeigt werden.

Konfigurationsänderungen manuell verwalten

Wenn Ihre Anwendung während einer bestimmten Konfigurationsänderung keine Ressourcen aktualisieren muss und Sie eine Leistungsbeschränkung haben, die den Neustart der Aktivität verhindert, können Sie erklären, dass Ihre Aktivität die Konfigurationsänderung selbst übernimmt, wodurch das System Ihren Neustart nicht durchführen kann Aktivität.

Diese Technik sollte jedoch als letzter Ausweg angesehen werden, wenn Sie Neustarts aufgrund einer Konfigurationsänderung vermeiden müssen. Dies wird für die meisten Anwendungen nicht empfohlen. Um diesen Ansatz zu android:configChanges , müssen wir den Knoten android:configChanges zur Aktivität in der AndroidManifest.xml hinzufügen :

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

Wenn sich nun eine dieser Konfigurationen ändert, wird die Aktivität nicht neu onConfigurationChanged() sondern empfängt stattdessen einen Aufruf an onConfigurationChanged() :

// Within the activity which receives these changes
// Checks the current device orientation, and toasts accordingly
@Override
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();
    }
}

Siehe den Abschnitt Umgang mit den Änderungsdokumenten . Weitere Informationen darüber, welche Konfigurationsänderungen Sie in Ihrer Aktivität ausführen können, finden Sie in der Dokumentation zu android: configChanges und in der Konfigurationsklasse .

Umgang mit AsyncTask

Problem:

  • Wenn nach dem AsyncTask eine Bildschirmrotation erfolgt, wird die Besitzeraktivität zerstört und neu erstellt.
  • Wenn die AsyncTask , möchte sie die möglicherweise nicht mehr gültige Benutzeroberfläche aktualisieren.

Lösung:

Mit Loaders kann man die Zerstörung / Wiederherstellung von Aktivitäten leicht überwinden.

Beispiel:

Hauptaktivität:

public class MainActivity extends AppCompatActivity 
        implements LoaderManager.LoaderCallbacks<Bitmap> {

    //Unique id for the loader
    private static final int MY_LOADER = 0; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LoaderManager loaderManager = getSupportLoaderManager();

        if(loaderManager.getLoader(MY_LOADER) == null) {
            loaderManager.initLoader(MY_LOADER, null, this).forceLoad();
        }
    }

    @Override
    public Loader<Bitmap> onCreateLoader(int id, Bundle args) {
        //Create a new instance of your Loader<Bitmap>
        MyLoader loader = new MyLoader(MainActivity.this);
        return loader;
    }

    @Override
    public void onLoadFinished(Loader<Bitmap> loader, Bitmap data) {
        // do something in the parent activity/service
        // i.e. display the downloaded image
        Log.d("MyAsyncTask", "Received result: ");
    }

    @Override
    public void onLoaderReset(Loader<Bitmap> loader) {

    }
}

AsyncTaskLoader:

public class MyLoader extends AsyncTaskLoader<Bitmap> {
    private WeakReference<Activity> motherActivity;

    public MyLoader(Activity activity) {
        super(activity);
        //We don't use this, but if you want you can use it, but remember, WeakReference
        motherActivity = new WeakReference<>(activity);
    }

    @Override
    public Bitmap loadInBackground() {
        // Do work. I.e download an image from internet to be displayed in gui.
        // i.e. return the downloaded gui
        return result;
    }
}

Hinweis:

Es ist wichtig, entweder die v4-Kompatibilitätsbibliothek zu verwenden oder nicht, aber nicht einen Teil des einen und einen Teil des anderen, da dies zu Kompilierungsfehlern führen kann. Um zu überprüfen, können Sie die Importe für android.support.v4.content und android.content (Sie sollten nicht beides haben).

Bildschirmsperre programmgesteuert sperren

Es ist sehr üblich, dass es während der Entwicklung sehr nützlich sein kann, den Bildschirm des Geräts während bestimmter Teile des Codes zu sperren / zu entsperren .

Wenn Sie beispielsweise ein Dialogfeld mit Informationen anzeigen, möchte der Entwickler möglicherweise die Bildschirmrotation sperren , um zu verhindern, dass das Dialogfeld geschlossen wird und die aktuelle Aktivität neu erstellt wird, um sie wieder zu entsperren , wenn das Dialogfeld geschlossen wird.

Obwohl wir aus dem Manifest eine Rotationssperre erreichen können, indem wir Folgendes tun:

<activity
    android:name=".TheActivity"
    android:screenOrientation="portrait"
    android:label="@string/app_name" >
</activity>

Man kann das auch programmgesteuert machen, indem man Folgendes tut:

public void lockDeviceRotation(boolean value) {
    if (value) {
        int currentOrientation = getResources().getConfiguration().orientation;
        if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
        }
    } else {
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
        }
    }
}

Und dann den folgenden Aufruf, um die Gerätedrehung zu sperren bzw. zu entsperren

lockDeviceRotation(true)

und

lockDeviceRotation(false) 


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow