Android-Speicher – Anwendungsfälle und Best Practices

Mit Android 10 wurde ein neues Speichermodell für Anwendungen namens Bereichsspeicher eingeführt, um Nutzern mehr Kontrolle über ihre Dateien zu geben und das Durcheinander zu reduzieren. Begrenzter Speicher ändert die Art und Weise, wie Apps Dateien im externen Speicher eines Geräts speichern und darauf zugreifen. Folgen Sie den Best Practices für gängige Speicheranwendungsfälle, die in diesem Leitfaden beschrieben werden, um die Migration Ihrer Anwendung zur Unterstützung von beschränktem Speicher zu erleichtern. Die Anwendungsfälle sind in zwei Kategorien unterteilt: Mediendateien verarbeiten und Nicht-Mediendateien verarbeiten.

Weitere Informationen zum Speichern und Abrufen von Dateien unter Android findest du in den Trainingsleitfäden für Speicher.

Mediendateien verarbeiten

In diesem Abschnitt werden einige der häufigsten Anwendungsfälle für die Verarbeitung von Mediendateien (Video-, Bild- und Audiodateien) beschrieben und der allgemeine Ansatz erläutert, den Ihre Anwendung verwenden kann. In der folgenden Tabelle werden die einzelnen Anwendungsfälle zusammengefasst und Links zu den einzelnen Abschnitten mit weiteren Details angegeben.

Anwendungsfall Zusammenfassung
Alle Bild- oder Videodateien anzeigen Verwende für alle Android-Versionen denselben Ansatz.
Bilder oder Videos aus einem bestimmten Ordner anzeigen Verwende für alle Android-Versionen denselben Ansatz.
Auf Standortinformationen aus Fotos zugreifen Verwenden Sie einen Ansatz, wenn Ihre Anwendung beschränkten Speicher verwendet. Verwenden Sie einen anderen Ansatz, wenn Ihre Anwendung den beschränkten Speicher deaktiviert.
Speicherort für neue Downloads festlegen Verwenden Sie einen Ansatz, wenn Ihre Anwendung beschränkten Speicher verwendet. Verwenden Sie einen anderen Ansatz, wenn Ihre Anwendung den beschränkten Speicher deaktiviert.
Mediendateien von Nutzern auf ein Gerät exportieren Verwende für alle Android-Versionen denselben Ansatz.
Mehrere Mediendateien in einem einzigen Vorgang ändern oder löschen Verwende einen Ansatz für Android 11. Bei Android 10 solltest du den beschränkten Speicher deaktivieren und stattdessen die Methode für Android 9 und niedriger verwenden.
Vorhandenes einzelnes Image importieren Verwende für alle Android-Versionen denselben Ansatz.
Ein einzelnes Bild aufnehmen Verwende für alle Android-Versionen denselben Ansatz.
Mediendateien mit anderen Apps teilen Verwende für alle Android-Versionen denselben Ansatz.
Mediendateien für eine bestimmte App freigeben Verwende für alle Android-Versionen denselben Ansatz.
Auf Dateien über Code oder Bibliotheken zugreifen, die direkte Dateipfade verwenden Verwende einen Ansatz für Android 11. Bei Android 10 solltest du den beschränkten Speicher deaktivieren und stattdessen die Methode für Android 9 und niedriger verwenden.

Bild- oder Videodateien aus mehreren Ordnern anzeigen

Verwenden Sie die query() API zum Abfragen einer Mediensammlung. Passen Sie die Parameter projection, selection, selectionArgs und sortOrder an, um die Mediendateien zu filtern oder zu sortieren.

Bilder oder Videos aus einem bestimmten Ordner anzeigen

Verwenden Sie diesen Ansatz:

  1. Fordern Sie gemäß den Best Practices unter App-Berechtigungen anfordern die Berechtigung READ_EXTERNAL_STORAGE an.
  2. Rufen Sie Mediendateien anhand des Werts von MediaColumns.DATA ab, der den absoluten Dateisystempfad zum Medienelement auf dem Laufwerk enthält.

Hinweis: Wenn Sie auf eine vorhandene Mediendatei zugreifen, können Sie den Wert der Spalte DATA in Ihrer Logik verwenden. Das liegt daran, dass dieser Wert einen gültigen Dateipfad hat. Gehen Sie jedoch nicht davon aus, dass die Datei immer verfügbar ist. Seien Sie auf den Umgang mit möglichen dateibasierten E/A-Fehlern vorbereitet.

Verwenden Sie zum Erstellen oder Aktualisieren einer Mediendatei jedoch nicht die Spalte DATA. Verwende stattdessen die Spalten DISPLAY_NAME und RELATIVE_PATH.

Auf Standortinformationen aus Fotos zugreifen

Wenn Ihre Anwendung beschränkten Speicher verwendet, führen Sie die Schritte im Abschnitt Standortinformationen in Fotos des Leitfadens zum Medienspeicher aus.

Speicherort für neue Downloads festlegen

Wenn Ihre Anwendung begrenzten Speicher verwendet, achten Sie auf den Speicherort, an dem Sie die heruntergeladenen Mediendateien speichern.

Wenn andere Apps Zugriff auf Dateien benötigen, sollten Sie klar definierte Mediensammlungen für Downloads oder Dokumentsammlungen verwenden.

Unter Android 11 und höher sind die Dateien in Ihrem externen app-spezifischen Verzeichnis nicht für andere Apps zugänglich, auch wenn Sie diese Dateien mit DownloadManager abrufen.

Nutzermediendateien auf ein Gerät exportieren

Legen Sie einen geeigneten Standardspeicherort für die Mediendateien von Nutzern fest:

Mehrere Mediendateien in einem einzigen Vorgang ändern oder löschen

Füge Logik ein, die auf den Android-Versionen deiner App basiert.

Unter Android 11

Verwenden Sie diesen Ansatz:

  1. Erstellen Sie mit MediaStore.createWriteRequest() oder MediaStore.createTrashRequest() einen ausstehenden Intent für die Schreib- oder Löschanfrage Ihrer App und fordern Sie dann den Nutzer auf, um die Berechtigung zum Bearbeiten einer Gruppe von Dateien zu erhalten, indem Sie den entsprechenden Intent aufrufen.
  2. Bewerten Sie die Antwort der Nutzenden:

    • Wenn die Berechtigung erteilt wurde, fahren Sie mit dem Ändern oder Löschen fort.
    • Wenn die Berechtigung nicht erteilt wurde, erklären Sie dem Nutzer, warum die Berechtigung für die Funktion in Ihrer App erforderlich ist.

Weitere Informationen zum Verwalten von Gruppen von Mediendateien mit diesen Methoden, die unter Android 11 und höher verfügbar sind

Mit Android 10

Wenn Ihre App auf Android 10 (API-Level 29) ausgerichtet ist, deaktivieren Sie den begrenzten Speicher und verwenden Sie für diesen Vorgang weiterhin den Ansatz für Android 9 und niedriger.

Wenn Sie Android 9 oder niedriger verwenden

Verwenden Sie diesen Ansatz:

  1. Fordern Sie gemäß den Best Practices unter App-Berechtigungen anfordern die Berechtigung WRITE_EXTERNAL_STORAGE an.
  2. Verwenden Sie die MediaStore API, um die Mediendateien zu ändern oder zu löschen.

Einzelnes Image importieren, das bereits vorhanden ist

Wenn Sie ein einzelnes Bild importieren möchten, das bereits vorhanden ist (z. B. um es als Foto für ein Nutzerprofil zu verwenden), kann Ihre Anwendung entweder ihre eigene UI für den Vorgang oder die Systemauswahl verwenden.

Ihre eigene Benutzeroberfläche präsentieren

Verwenden Sie diesen Ansatz:

  1. Fordern Sie gemäß den Best Practices unter App-Berechtigungen anfordern die Berechtigung READ_EXTERNAL_STORAGE an.
  2. Verwenden Sie die query() API, um eine Mediensammlung abzufragen.
  3. Lassen Sie die Ergebnisse in der benutzerdefinierten UI Ihrer App anzeigen.

Systemauswahl verwenden

Verwenden Sie den Intent ACTION_GET_CONTENT, bei dem der Nutzer aufgefordert wird, ein Bild für den Import auszuwählen.

Wenn Sie die Bildtypen filtern möchten, die dem Nutzer in der Systemauswahl zur Auswahl angezeigt werden, können Sie setType() oder EXTRA_MIME_TYPES verwenden.

Einzelnes Bild aufnehmen

Wenn du ein einzelnes Bild erfassen möchtest, das in deiner App verwendet werden soll (z. B. als Foto für ein Nutzerprofil), verwende den ACTION_IMAGE_CAPTURE-Intent, um den Nutzer aufzufordern, ein Foto mit der Kamera des Geräts aufzunehmen. Das aufgenommene Foto wird in der Tabelle MediaStore.Images gespeichert.

Mediendateien mit anderen Apps teilen

Verwenden Sie die Methode insert(), um Einträge direkt im MediaStore hinzuzufügen. Weitere Informationen finden Sie im Leitfaden zum Medienspeicher im Abschnitt Element hinzufügen.

Mediendateien mit einer bestimmten App teilen

Verwenden Sie die Android-Komponente FileProvider wie unter Dateifreigabe einrichten beschrieben.

Auf Dateien über Code oder Bibliotheken zugreifen, die direkte Dateipfade verwenden

Füge Logik ein, die auf den Android-Versionen deiner App basiert.

Unter Android 11

Verwenden Sie diesen Ansatz:

  1. Fordern Sie gemäß den Best Practices unter App-Berechtigungen anfordern die Berechtigung READ_EXTERNAL_STORAGE an.
  2. Sie können über direkte Dateipfade auf die Dateien zugreifen.

Weitere Informationen finden Sie im Abschnitt zum Öffnen von Mediendateien über direkte Dateipfade.

Mit Android 10

Wenn Ihre App auf Android 10 (API-Level 29) ausgerichtet ist, deaktivieren Sie den begrenzten Speicher und verwenden Sie für diesen Vorgang weiterhin den Ansatz für Android 9 und niedriger.

Wenn Sie Android 9 oder niedriger verwenden

Verwenden Sie diesen Ansatz:

  1. Fordern Sie gemäß den Best Practices unter App-Berechtigungen anfordern die Berechtigung WRITE_EXTERNAL_STORAGE an.
  2. Sie können über direkte Dateipfade auf die Dateien zugreifen.

Nicht-Mediendateien verarbeiten

In diesem Abschnitt werden einige der häufigsten Anwendungsfälle für die Verarbeitung von Nicht-Mediendateien beschrieben und der allgemeine Ansatz erläutert, den Ihre Anwendung verwenden kann. In der folgenden Tabelle werden die einzelnen Anwendungsfälle zusammengefasst und Links zu den einzelnen Abschnitten mit weiteren Details angegeben.

Anwendungsfall Zusammenfassung
Dokumentdateien öffnen Verwende für alle Android-Versionen denselben Ansatz.
In Dateien auf sekundären Speicher-Volumes schreiben Verwende einen Ansatz für Android 11. Wähle für frühere Android-Versionen einen anderen Ansatz.
Vorhandene Dateien von einem alten Speicherort migrieren Migrieren Sie Ihre Dateien nach Möglichkeit auf einen begrenzten Speicher. Bei Bedarf können Sie den beschränkten Speicher für Android 10 deaktivieren.
Inhalte mit anderen Apps teilen Verwende für alle Android-Versionen denselben Ansatz.
Nicht-Mediendateien im Cache speichern Verwende für alle Android-Versionen denselben Ansatz.
Nicht-Mediendateien auf ein Gerät exportieren Verwenden Sie einen Ansatz, wenn Ihre Anwendung beschränkten Speicher verwendet. Verwenden Sie einen anderen Ansatz, wenn Ihre Anwendung den beschränkten Speicher deaktiviert.

Öffnen einer Dokumentdatei

Verwenden Sie den Intent ACTION_OPEN_DOCUMENT, um den Nutzer aufzufordern, eine Datei auszuwählen, die mit der Systemauswahl geöffnet werden soll. Wenn Sie die Dateitypen filtern möchten, die dem Nutzer in der Systemauswahl zur Auswahl angezeigt werden, können Sie setType() oder EXTRA_MIME_TYPES verwenden.

Mit dem folgenden Code können Sie beispielsweise nach allen PDF-, ODT- und TXT-Dateien suchen:

Kotlin

startActivityForResult(
        Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "*/*"
            putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(
                    "application/pdf", // .pdf
                    "application/vnd.oasis.opendocument.text", // .odt
                    "text/plain" // .txt
            ))
        },
        REQUEST_CODE
      )

Java

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
                "application/pdf", // .pdf
                "application/vnd.oasis.opendocument.text", // .odt
                "text/plain" // .txt
        });
        startActivityForResult(intent, REQUEST_CODE);

In Dateien auf sekundären Speicher-Volumes schreiben

Zu den sekundären Speicher-Volumes gehören SD-Karten. Mithilfe der Klasse StorageVolume können Sie auf Informationen zu einem bestimmten Speicher-Volume zugreifen.

Binde Logik ein, die auf der Android-Version basiert, auf der deine App ausgeführt wird.

Mit Android 11

Verwenden Sie diesen Ansatz:

  1. Verwenden Sie das Modell für begrenzten Speicher.
  2. Ausrichtung auf Android 10 (API-Level 29) oder niedriger.
  3. Deklarieren Sie die Berechtigung WRITE_EXTERNAL_STORAGE.
  4. Sie haben folgende Möglichkeiten:
    • Dateizugriff mit der MediaStore API.
    • Direkter Zugriff auf den Dateipfad über APIs wie File oder fopen().

Mit älteren Versionen ausgeführt

Verwenden Sie das Storage Access Framework. Damit können Nutzer den Speicherort auf einem sekundären Speicher-Volume auswählen, an dem Ihre Anwendung die Datei schreiben kann.

Vorhandene Dateien von einem alten Speicherort migrieren

Ein Verzeichnis gilt als Legacy-Speicherort, wenn es weder ein anwendungsspezifisches Verzeichnis noch ein öffentliches freigegebenes Verzeichnis ist. Wenn Ihre Anwendung Dateien an einem Legacy-Speicherort erstellt oder nutzt, empfehlen wir, die Dateien der Anwendung an Speicherorte zu migrieren, auf die mit eingeschränktem Speicher zugegriffen werden kann. Außerdem sollten Sie alle erforderlichen Änderungen an der Anwendung vornehmen, um mit Dateien im beschränkten Speicher zu arbeiten.

Zugriff auf den alten Speicherort für die Datenmigration beibehalten

Ihre Anwendung muss weiterhin Zugriff auf den Legacy-Speicherort haben, um Anwendungsdateien an Speicherorte zu migrieren, auf die mit eingeschränktem Speicher zugegriffen werden kann. Welche Methode Sie verwenden sollten, hängt vom Ziel-API-Level Ihrer App ab.

Wenn deine App auf Android 11 ausgerichtet ist
  1. Setze das Flag preserveLegacyExternalStorage auf true, um das alte Speichermodell beizubehalten. So kann deine App die Daten eines Nutzers migrieren, wenn er auf die neue Version deiner App aktualisiert wird, die auf Android 11 ausgerichtet ist.

  2. Fahren Sie fort, den beschränkten Speicher zu deaktivieren, damit Ihre App weiterhin auf Ihre Dateien am alten Speicherort auf Android 10-Geräten zugreifen kann.

Wenn deine App auf Android 10 ausgerichtet ist

Deaktivieren Sie den begrenzten Speicher, um die Verwaltung des App-Verhaltens in verschiedenen Android-Versionen zu erleichtern.

App-Daten migrieren

Wenn Ihre Anwendung für die Migration bereit ist, verwenden Sie den folgenden Ansatz:

  1. Ausrichtung auf Android 10 oder niedriger.
  2. Deaktivieren Sie den begrenzten Speicher, damit Ihre Anwendung auf die zu migrierenden Dateien zugreifen kann.
  3. Stellen Sie Code bereit, der die File API verwendet, um Dateien von ihrem aktuellen Speicherort unter /sdcard/ an einen Speicherort zu verschieben, auf den mit eingeschränktem Speicher zugegriffen werden kann:

    1. Verschieben Sie alle privaten Anwendungsdateien in das Verzeichnis, das von der Methode getExternalFilesDir() zurückgegeben wird.
    2. Verschieben Sie alle freigegebenen Nicht-Mediendateien in ein anwendungsspezifisches Unterverzeichnis des Verzeichnisses Downloads/.
  4. Entfernen Sie die alten Speicherverzeichnisse der Anwendung aus dem Verzeichnis /sdcard/.

Nachdem Nutzer die neue Version deiner App installiert haben, schließen sie die Datenmigration auf ihren Geräten ab. Sie können den Migrationsprozess für Ihre gesamte Nutzerbasis überwachen, indem Sie ein Analyseereignis erstellen.

Nachdem Nutzer ihre Daten migriert haben, kannst du ein weiteres Update für deine App veröffentlichen, die auf Android 11 ausgerichtet ist.

Inhalte mit anderen Apps teilen

Um die Dateien Ihrer App für eine einzelne andere App freizugeben, verwenden Sie ein FileProvider. Für Anwendungen, die alle Dateien untereinander freigeben müssen, sollten Sie für jede Anwendung einen Contentanbieter verwenden und die Daten synchronisieren, wenn Anwendungen der Sammlung hinzugefügt werden.

Nicht-Mediendateien im Cache speichern

Welche Methode Sie verwenden sollten, hängt von der Art der Dateien ab, die Sie im Cache speichern müssen.

Nicht-Mediendateien auf ein Gerät exportieren

Legen Sie einen geeigneten Standardspeicherort zum Speichern von Nicht-Mediendateien fest. Nutzern erlauben, Dateien aus anwendungsspezifischen Verzeichnissen an einen allgemeineren Ort zu exportieren Verwenden Sie die Downloads oder Dokumentsammlungen von MediaStore, um Nicht-Mediendateien auf das Gerät zu exportieren.

Zugewiesenen Speicher vorübergehend deaktivieren

Bevor Ihre App vollständig mit bereichsspezifischem Speicher kompatibel ist, können Sie diese Funktion vorübergehend deaktivieren, sowohl in Ihren Tests als auch in Ihrer Produktionsanwendung.

Von Tests abmelden

Unter Android 10 (API-Level 29) und höher werden die Tests deiner App standardmäßig in einer Speicher-Sandbox ausgeführt. Diese Sandbox verhindert, dass Ihre Anwendung auf Dateien außerhalb des anwendungsspezifischen Verzeichnisses und öffentlich freigegebenen Verzeichnisse zugreift.

Wenn ein Test Dateien für den Host ausgibt, z. B. Screenshots, Debugging-Daten, Abdeckungsdaten oder Leistungsmesswerte, können Sie diese Dateien in globale Verzeichnisse schreiben. Fügen Sie dazu das folgende Flag dem entsprechenden Speicher hinzu, der am instrument aufruft:

-e no-isolated-storage 1

Dieses Flag wirkt sich auf das gesamte Verhalten des instrumentierten Testlaufs sowie auf den gesamten aufgerufenen Testcode aus. Wenn Sie dieses Flag verwenden, können Sie daher nicht prüfen, ob Ihre Anwendung mit begrenztem Speicher kompatibel ist. Für die Testausgabe ist es besser, stattdessen in einen App-bezogenen Speicher zu schreiben, der für die Shell lesbar ist. Anschließend können Sie dieses Verzeichnis auf Anwendungsebene abrufen. Rufen Sie getExternalMediaDirs() auf, um zu ermitteln, aus welchem Verzeichnis abgerufen werden soll.

In der Produktions-App deaktivieren

Wenn deine App auf Android 10 (API-Level 29) oder niedriger ausgerichtet ist, kannst du den beschränkten Speicher in deiner Produktions-App vorübergehend deaktivieren. Wenn deine App jedoch auf Android 10 ausgerichtet ist, musst du in der Manifestdatei deiner App den Wert von requestLegacyExternalStorage auf true setzen:

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting
       Android 10. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

Wenn Sie testen möchten, wie sich eine App, die auf Android 10 oder niedriger ausgerichtet ist, bei Verwendung von begrenztem Speicher verhält, können Sie das Verhalten aktivieren. Dazu setzen Sie den Wert von requestLegacyExternalStorage auf false. Wenn Sie die Tests auf einem Gerät mit Android 11 ausführen, können Sie auch App-Kompatibilitäts-Flags verwenden, um das Verhalten Ihrer App mit oder ohne bereichsspezifischen Speicher zu testen.

Weitere Informationen

Weitere Informationen zum Android-Speicherplatz finden Sie in den folgenden Ressourcen:

Blogposts