In vielen Fällen erstellt Ihre App Dateien, auf die andere Apps nicht zugreifen müssen oder nicht zugreifen sollten. Das System bietet die folgenden Speicherorte für solche appspezifischen Dateien:
Interne Speicherverzeichnisse:Diese Verzeichnisse umfassen sowohl einen dedizierten Speicherort für persistente Dateien als auch einen weiteren Speicherort für Cache-Daten. Das System verhindert, dass andere Apps auf diese Speicherorte zugreifen. Unter Android 10 (API-Level 29) und höher sind diese Speicherorte verschlüsselt. Diese Eigenschaften machen diese Speicherorte zu einem guten Ort, um vertrauliche Daten zu speichern, auf die nur Ihre App selbst zugreifen kann.
Externe Speicherverzeichnisse: Diese Verzeichnisse umfassen sowohl einen dedizierten Speicherort für persistente Dateien als auch einen weiteren Speicherort für Cache-Daten. Es ist zwar möglich, dass eine andere App auf diese Verzeichnisse zugreift, wenn sie die entsprechenden Berechtigungen hat, aber die in diesen Verzeichnissen gespeicherten Dateien sind nur für die Verwendung durch Ihre App vorgesehen. Wenn Sie Dateien erstellen möchten, auf die andere Apps zugreifen können, sollte Ihre App diese Dateien stattdessen im freigegebenen Speicher des externen Speichers speichern.
Wenn der Nutzer deine App deinstalliert, werden die im App-spezifischen Speicher gespeicherten Dateien entfernt. Aus diesem Grund sollten Sie diesen Speicher nicht für Daten verwenden, die der Nutzer unabhängig von Ihrer App behalten möchte. Wenn Ihre App beispielsweise das Aufnehmen von Fotos ermöglicht, erwartet der Nutzer, dass er auch nach der Deinstallation Ihrer App auf diese Fotos zugreifen kann. Sie sollten daher stattdessen den freigegebenen Speicher verwenden, um diese Dateitypen in der entsprechenden Mediensammlung zu speichern.
In den folgenden Abschnitten wird beschrieben, wie Sie Dateien in App-spezifischen Verzeichnissen speichern und darauf zugreifen.
Zugriff über internen Speicher
Für jede App stellt das System Verzeichnisse im internen Speicher bereit, in denen eine App ihre Dateien organisieren kann. Ein Verzeichnis ist für die nichtflüchtigen Dateien Ihrer App vorgesehen, ein anderes enthält die im Cache gespeicherten Dateien Ihrer App. Ihre Anwendung benötigt keine Systemberechtigungen, um Dateien in diesen Verzeichnissen zu lesen und zu schreiben.
Andere Apps können nicht auf Dateien im internen Speicher zugreifen. Daher eignet sich der interne Speicher gut für App-Daten, auf die andere Apps nicht zugreifen sollen.
Beachten Sie jedoch, dass diese Verzeichnisse in der Regel klein sind. Bevor Ihre App anwendungsspezifische Dateien in den internen Speicher schreibt, sollte sie den freien Speicherplatz auf dem Gerät abfragen.
Auf persistente Dateien zugreifen
Die normalen, nichtflüchtigen Dateien Ihrer App befinden sich in einem Verzeichnis, auf das Sie über das Attribut filesDir eines Kontextobjekts zugreifen können. Das Framework bietet mehrere Methoden, mit denen Sie auf Dateien in diesem Verzeichnis zugreifen und sie dort speichern können.
Auf Dateien zugreifen und sie speichern
Sie können die File API verwenden, um auf Dateien zuzugreifen und sie zu speichern.
Damit die Leistung Ihrer App nicht beeinträchtigt wird, sollten Sie dieselbe Datei nicht mehrmals öffnen und schließen.
Das folgende Code-Snippet zeigt, wie die File API verwendet wird:
Kotlin
val file = File(context.filesDir, filename)
Java
File file = new File(context.getFilesDir(), filename);
Datei mithilfe eines Streams speichern
Als Alternative zur Verwendung der File API können Sie openFileOutput() aufrufen, um einen FileOutputStream zu erhalten, der in eine Datei im Verzeichnis filesDir schreibt.
Das folgende Code-Snippet zeigt, wie Text in eine Datei geschrieben wird:
Kotlin
val filename = "myfile" val fileContents = "Hello world!" context.openFileOutput(filename, Context.MODE_PRIVATE).use { it.write(fileContents.toByteArray()) }
Java
String filename = "myfile"; String fileContents = "Hello world!"; try (FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE)) { fos.write(fileContents.toByteArray()); }
Wenn Sie anderen Apps den Zugriff auf Dateien erlauben möchten, die in diesem Verzeichnis im internen Speicher gespeichert sind, verwenden Sie ein FileProvider mit dem Attribut FLAG_GRANT_READ_URI_PERMISSION.
Über einen Stream auf eine Datei zugreifen
Verwenden Sie openFileInput(), um eine Datei als Stream zu lesen:
Kotlin
context.openFileInput(filename).bufferedReader().useLines { lines -> lines.fold("") { some, text -> "$some\n$text" } }
Java
FileInputStream fis = context.openFileInput(filename); InputStreamReader inputStreamReader = new InputStreamReader(fis, StandardCharsets.UTF_8); StringBuilder stringBuilder = new StringBuilder(); try (BufferedReader reader = new BufferedReader(inputStreamReader)) { String line = reader.readLine(); while (line != null) { stringBuilder.append(line).append('\n'); line = reader.readLine(); } } catch (IOException e) { // Error occurred when opening raw file for reading. } finally { String contents = stringBuilder.toString(); }
Liste der Dateien ansehen
Sie können ein Array mit den Namen aller Dateien im Verzeichnis filesDir abrufen, indem Sie fileList() aufrufen, wie im folgenden Code-Snippet gezeigt:
Kotlin
var files: Array<String> = context.fileList()
Java
Array<String> files = context.fileList();
Verschachtelte Verzeichnisse erstellen
Sie können auch verschachtelte Verzeichnisse erstellen oder ein inneres Verzeichnis öffnen. Rufen Sie dazu getDir() in Kotlin-basiertem Code auf oder übergeben Sie das Stammverzeichnis und einen neuen Verzeichnisnamen an einen File-Konstruktor in Java-basiertem Code:
Kotlin
context.getDir(dirName, Context.MODE_PRIVATE)
Java
File directory = context.getFilesDir(); File file = new File(directory, filename);
Cache-Dateien erstellen
Wenn du sensible Daten nur vorübergehend speichern musst, solltest du das dafür vorgesehene Cache-Verzeichnis der App im internen Speicher verwenden. Wie bei allen App-spezifischen Speichern werden die in diesem Verzeichnis gespeicherten Dateien entfernt, wenn der Nutzer deine App deinstalliert. Die Dateien in diesem Verzeichnis können jedoch auch früher entfernt werden.
Rufen Sie File.createTempFile() auf, um eine im Cache gespeicherte Datei zu erstellen:
Kotlin
File.createTempFile(filename, null, context.cacheDir)
Java
File.createTempFile(filename, null, context.getCacheDir());
Ihre Anwendung greift auf eine Datei in diesem Verzeichnis über das Attribut cacheDir eines Kontextobjekts und die File API zu:
Kotlin
val cacheFile = File(context.cacheDir, filename)
Java
File cacheFile = new File(context.getCacheDir(), filename);
Cache-Dateien entfernen
Auch wenn Android Cache-Dateien manchmal selbst löscht, solltet ihr euch nicht darauf verlassen, dass das System diese Dateien für euch bereinigt. Sie sollten die Cache-Dateien Ihrer App immer im internen Speicher aufbewahren.
Verwenden Sie eine der folgenden Methoden, um eine Datei aus dem Cache-Verzeichnis im internen Speicher zu entfernen:
Die Methode
delete()für einFile-Objekt, das die Datei darstellt:Kotlin
cacheFile.delete()
Java
cacheFile.delete();
Die Methode
deleteFile()des App-Kontexts, wobei der Name der Datei übergeben wird:Kotlin
context.deleteFile(cacheFileName)
Java
context.deleteFile(cacheFileName);
Zugriff über externen Speicher
Wenn der interne Speicher nicht genügend Platz für App-spezifische Dateien bietet, solltest du stattdessen externen Speicher verwenden. Das System stellt Verzeichnisse im externen Speicher bereit, in denen eine App Dateien organisieren kann, die nur innerhalb Ihrer App für den Nutzer nützlich sind. Ein Verzeichnis ist für die nichtflüchtigen Dateien Ihrer App vorgesehen, ein anderes enthält die im Cache gespeicherten Dateien Ihrer App.
Unter Android 4.4 (API-Level 19) oder höher muss Ihre App keine speicherbezogenen Berechtigungen anfordern, um auf App-spezifische Verzeichnisse im externen Speicher zuzugreifen. Die in diesen Verzeichnissen gespeicherten Dateien werden entfernt, wenn deine App deinstalliert wird.
Auf Geräten mit Android 9 (API-Level 28) oder niedriger kann Ihre App auf die App-spezifischen Dateien anderer Apps zugreifen, sofern Ihre App die entsprechenden Speicherberechtigungen hat. Damit Nutzer mehr Kontrolle über ihre Dateien haben und um die Anzahl der Dateien zu begrenzen, erhalten Apps, die auf Android 10 (API-Level 29) und höher ausgerichtet sind, standardmäßig einen begrenzten Zugriff auf den externen Speicher, auch begrenzter Speicher genannt. Wenn der begrenzte Speicher aktiviert ist, können Apps nicht auf die App-spezifischen Verzeichnisse anderer Apps zugreifen.
Prüfen, ob Speicherplatz verfügbar ist
Da sich der externe Speicher auf einem physischen Volume befindet, das der Nutzer möglicherweise entfernen kann, sollten Sie prüfen, ob das Volume zugänglich ist, bevor Sie versuchen, app-spezifische Daten aus dem externen Speicher zu lesen oder in diesen zu schreiben.
Sie können den Status des Volumes abfragen, indem Sie Environment.getExternalStorageState() aufrufen.
Wenn der zurückgegebene Status MEDIA_MOUNTED lautet, können Sie anwendungsspezifische Dateien im externen Speicher lesen und schreiben. Wenn der Wert MEDIA_MOUNTED_READ_ONLY lautet, können Sie diese Dateien nur lesen.
Die folgenden Methoden sind beispielsweise nützlich, um die Speicherverfügbarkeit zu ermitteln:
Kotlin
// Checks if a volume containing external storage is available // for read and write. fun isExternalStorageWritable(): Boolean { return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED } // Checks if a volume containing external storage is available to at least read. fun isExternalStorageReadable(): Boolean { return Environment.getExternalStorageState() in setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY) }
Java
// Checks if a volume containing external storage is available // for read and write. private boolean isExternalStorageWritable() { return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); } // Checks if a volume containing external storage is available to at least read. private boolean isExternalStorageReadable() { return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) || Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY); }
Verwende auf Geräten ohne wechselbaren externen Speicher den folgenden Befehl, um ein virtuelles Volume zum Testen der Logik für die Verfügbarkeit des externen Speichers zu aktivieren:
adb shell sm set-virtual-disk true
Physischen Speicherort auswählen
Manchmal bietet ein Gerät, das eine Partition seines internen Speichers als externen Speicher zuweist, auch einen SD-Kartensteckplatz. Das bedeutet, dass das Gerät mehrere physische Volumes hat, die externen Speicher enthalten könnten. Sie müssen also auswählen, welches Volume für Ihren App-spezifischen Speicher verwendet werden soll.
Rufen Sie ContextCompat.getExternalFilesDirs() auf, um auf die verschiedenen Standorte zuzugreifen.
Wie im Code-Snippet gezeigt, wird das erste Element im zurückgegebenen Array als primäres externes Speichervolume betrachtet. Verwenden Sie dieses Volume, sofern es nicht voll oder nicht verfügbar ist.
Kotlin
val externalStorageVolumes: Array<out File> = ContextCompat.getExternalFilesDirs(applicationContext, null) val primaryExternalStorage = externalStorageVolumes[0]
Java
File[] externalStorageVolumes = ContextCompat.getExternalFilesDirs(getApplicationContext(), null); File primaryExternalStorage = externalStorageVolumes[0];
Auf persistente Dateien zugreifen
Wenn du auf app-spezifische Dateien im externen Speicher zugreifen möchtest, rufe getExternalFilesDir() auf.
Damit die Leistung Ihrer App nicht beeinträchtigt wird, sollten Sie dieselbe Datei nicht mehrmals öffnen und schließen.
Das folgende Code-Snippet zeigt, wie getExternalFilesDir() aufgerufen wird:
Kotlin
val appSpecificExternalDir = File(context.getExternalFilesDir(null), filename)
Java
File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);
Cache-Dateien erstellen
Wenn du eine app-spezifische Datei zum Cache im externen Speicher hinzufügen möchtest, rufe einen Verweis auf externalCacheDir ab:
Kotlin
val externalCacheFile = File(context.externalCacheDir, filename)
Java
File externalCacheFile = new File(context.getExternalCacheDir(), filename);
Cache-Dateien entfernen
Wenn Sie eine Datei aus dem externen Cache-Verzeichnis entfernen möchten, verwenden Sie die Methode delete() für ein File-Objekt, das die Datei darstellt:
Kotlin
externalCacheFile.delete()
Java
externalCacheFile.delete();
Medieninhalte
Wenn Ihre App mit Mediendateien arbeitet, die nur innerhalb Ihrer App einen Mehrwert für den Nutzer bieten, sollten Sie sie in app-spezifischen Verzeichnissen im externen Speicher speichern, wie im folgenden Code-Snippet gezeigt:
Kotlin
fun getAppSpecificAlbumStorageDir(context: Context, albumName: String): File? { // Get the pictures directory that's inside the app-specific directory on // external storage. val file = File(context.getExternalFilesDir( Environment.DIRECTORY_PICTURES), albumName) if (!file?.mkdirs()) { Log.e(LOG_TAG, "Directory not created") } return file }
Java
@Nullable File getAppSpecificAlbumStorageDir(Context context, String albumName) { // Get the pictures directory that's inside the app-specific directory on // external storage. File file = new File(context.getExternalFilesDir( Environment.DIRECTORY_PICTURES), albumName); if (file == null || !file.mkdirs()) { Log.e(LOG_TAG, "Directory not created"); } return file; }
Es ist wichtig, dass Sie Verzeichnisnamen verwenden, die von API-Konstanten wie DIRECTORY_PICTURES bereitgestellt werden.
Diese Verzeichnisnamen sorgen dafür, dass die Dateien vom System richtig verarbeitet werden.
Wenn keiner der vordefinierten Unterverzeichnisnamen für Ihre Dateien geeignet ist, können Sie stattdessen null an getExternalFilesDir() übergeben. Dadurch wird das anwendungsspezifische Stammverzeichnis im externen Speicher zurückgegeben.
Verfügbaren Speicherplatz abfragen
Viele Nutzer haben nicht viel Speicherplatz auf ihren Geräten. Deine App sollte daher sparsam mit Speicherplatz umgehen.
Wenn ihr im Voraus wisst, wie viele Daten ihr speichern werdet, könnt ihr durch Aufrufen von getAllocatableBytes() herausfinden, wie viel Speicherplatz das Gerät eurer App zur Verfügung stellen kann.
Der Rückgabewert von getAllocatableBytes() ist möglicherweise größer als der aktuelle verfügbare Speicherplatz auf dem Gerät. Das liegt daran, dass das System Dateien identifiziert hat, die aus den Cache-Verzeichnissen anderer Apps entfernt werden können.
Wenn genügend Speicherplatz zum Speichern der Daten deiner App vorhanden ist, rufe allocateBytes() auf.
Andernfalls kann Ihre App den Nutzer auffordern, einige Dateien vom Gerät zu entfernen oder alle Cache-Dateien vom Gerät zu entfernen.
Das folgende Code-Snippet zeigt ein Beispiel dafür, wie Ihre App den freien Speicherplatz auf dem Gerät abfragen kann:
Kotlin
// App needs 10 MB within internal storage. const val NUM_BYTES_NEEDED_FOR_MY_APP = 1024 * 1024 * 10L; val storageManager = applicationContext.getSystemService<StorageManager>()!! val appSpecificInternalDirUuid: UUID = storageManager.getUuidForPath(filesDir) val availableBytes: Long = storageManager.getAllocatableBytes(appSpecificInternalDirUuid) if (availableBytes >= NUM_BYTES_NEEDED_FOR_MY_APP) { storageManager.allocateBytes( appSpecificInternalDirUuid, NUM_BYTES_NEEDED_FOR_MY_APP) } else { val storageIntent = Intent().apply { // To request that the user remove all app cache files instead, set // "action" to ACTION_CLEAR_APP_CACHE. action = ACTION_MANAGE_STORAGE } }
Java
// App needs 10 MB within internal storage. private static final long NUM_BYTES_NEEDED_FOR_MY_APP = 1024 * 1024 * 10L; StorageManager storageManager = getApplicationContext().getSystemService(StorageManager.class); UUID appSpecificInternalDirUuid = storageManager.getUuidForPath(getFilesDir()); long availableBytes = storageManager.getAllocatableBytes(appSpecificInternalDirUuid); if (availableBytes >= NUM_BYTES_NEEDED_FOR_MY_APP) { storageManager.allocateBytes( appSpecificInternalDirUuid, NUM_BYTES_NEEDED_FOR_MY_APP); } else { // To request that the user remove all app cache files instead, set // "action" to ACTION_CLEAR_APP_CACHE. Intent storageIntent = new Intent(); storageIntent.setAction(ACTION_MANAGE_STORAGE); }
Speicherverwaltungsaktivität erstellen
In deiner App kann eine benutzerdefinierte Aktivität deklariert und erstellt werden, mit der der Nutzer nach dem Start die Daten verwalten kann, die deine App auf dem Gerät des Nutzers gespeichert hat. Diese benutzerdefinierte Aktivität „Speicherplatz verwalten“ deklarieren Sie mit dem Attribut android:manageSpaceActivity in der Manifestdatei. Dateimanager-Apps können diese Aktivität aufrufen, auch wenn Ihre App die Aktivität nicht exportiert, d. h. wenn Ihre Aktivität android:exported auf false setzt.
Nutzer bitten, einige Gerätedateien zu entfernen
Wenn du den Nutzer auffordern möchtest, Dateien auf dem Gerät zum Entfernen auszuwählen, rufe einen Intent auf, der die Aktion ACTION_MANAGE_STORAGE enthält. Dieser Intent zeigt dem Nutzer eine Aufforderung an. Falls gewünscht, kann in dieser Aufforderung der verfügbare Speicherplatz auf dem Gerät angezeigt werden. Verwenden Sie das Ergebnis der folgenden Berechnung, um diese nutzerfreundlichen Informationen anzuzeigen:
StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()
Nutzer bitten, alle Cache-Dateien zu entfernen
Alternativ kannst du den Nutzer bitten, die Cache-Dateien aller Apps auf dem Gerät zu löschen. Rufen Sie dazu einen Intent auf, der die Intent-Aktion ACTION_CLEAR_APP_CACHE enthält.
Zusätzliche Ressourcen
Weitere Informationen zum Speichern von Dateien im Speicher des Geräts finden Sie in den folgenden Ressourcen.