Android
Orientierungsänderungen
Suche…
Bemerkungen
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)