In molti casi, la tua app crea file a cui altre app non devono accedere o non dovrebbero accedere. Il sistema fornisce le seguenti posizioni per l'archiviazione di questi file specifici dell'app:
Directory di archiviazione interna: queste directory includono sia una posizione dedicata per l'archiviazione di file persistenti sia un'altra posizione per l'archiviazione dei dati della cache. Il sistema impedisce ad altre app di accedere a queste posizioni e, su Android 10 (livello API 29) e versioni successive, queste posizioni sono criptate. Queste caratteristiche rendono queste posizioni un buon posto per archiviare dati sensibili a cui solo la tua app può accedere.
Directory di archiviazione esterna: queste directory includono sia una posizione dedicata per l'archiviazione di file persistenti sia un'altra posizione per l'archiviazione dei dati della cache. Sebbene sia possibile che un'altra app acceda a queste directory se dispone delle autorizzazioni appropriate, i file archiviati in queste directory sono destinati all'uso esclusivo da parte della tua app. Se intendi specificamente creare file a cui altre app devono poter accedere, la tua app deve archiviare questi file nella parte di archiviazione condivisa dell'archiviazione esterna invece.
Quando l'utente disinstalla la tua app, i file salvati nell'archivio specifico dell'app vengono rimossi. A causa di questo comportamento, non devi utilizzare questo spazio di archiviazione per salvare elementi che l'utente si aspetta che persistano indipendentemente dalla tua app. Ad esempio, se la tua app consente agli utenti di scattare foto, l'utente si aspetta di poter accedere a queste foto anche dopo aver disinstallato l'app. Pertanto, devi utilizzare l'archivio condiviso per salvare questi tipi di file nella raccolta multimediale appropriata.
Le sezioni seguenti descrivono come archiviare e accedere ai file all'interno di directory specifiche dell'app.
Accesso dall'archivio interno
Per ogni app, il sistema fornisce directory all'interno dell'archivio interno in cui un' app può organizzare i propri file. Una directory è progettata per i file persistenti dell'app e un'altra contiene i file memorizzati nella cache dell'app. La tua app non richiede alcuna autorizzazione di sistema per leggere e scrivere file in queste directory.
Le altre app non possono accedere ai file archiviati nell'archivio interno. Questo rende l'archivio interno un buon posto per i dati dell'app a cui altre app non devono accedere.
Tieni presente, tuttavia, che queste directory tendono a essere piccole. Prima di scrivere file specifici dell'app nell'archivio interno, l'app deve eseguire una query sullo spazio libero sul dispositivo.
Accedere ai file persistenti
I file persistenti ordinari dell'app si trovano in una directory a cui puoi
accedere utilizzando la filesDir
proprietà di un oggetto contesto. Il framework fornisce diversi metodi per aiutarti ad
accedere e archiviare i file in questa directory.
Accedere e archiviare i file
Puoi utilizzare l'API File per accedere e archiviare i file.
Per contribuire a mantenere le prestazioni dell'app, non aprire e chiudere lo stesso file più volte.
Il seguente snippet di codice mostra come utilizzare l'API File:
Kotlin
val file = File(context.filesDir, filename)
Java
File file = new File(context.getFilesDir(), filename);
Archiviare un file utilizzando uno stream
In alternativa all'utilizzo dell'API File, puoi chiamare
openFileOutput()
per ottenere un FileOutputStream che scrive
in un file all'interno della directory filesDir.
Il seguente snippet di codice mostra come scrivere del testo in un file:
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()); }
Per consentire ad altre app di accedere ai file archiviati in
questa directory all'interno dell'archivio interno, utilizza un
FileProvider con l'attributo
FLAG_GRANT_READ_URI_PERMISSION.
Accedere a un file utilizzando uno stream
Per leggere un file come stream, utilizza
openFileInput():
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(); }
Visualizzare l'elenco dei file
Puoi ottenere un array contenente i nomi di tutti i file all'interno della filesDir
directory chiamando
fileList(), come mostrato in
questo snippet di codice:
Kotlin
var files: Array<String> = context.fileList()
Java
Array<String> files = context.fileList();
Creare directory nidificate
Puoi anche creare directory nidificate o aprire una directory interna chiamando
getDir() nel codice basato su Kotlin o passando la directory principale e un nuovo nome di directory a un costruttore File
nel codice basato su Java:
Kotlin
context.getDir(dirName, Context.MODE_PRIVATE)
Java
File directory = context.getFilesDir(); File file = new File(directory, filename);
Creare file della cache
Se devi archiviare dati sensibili solo temporaneamente, devi utilizzare la directory della cache designata dell'app all'interno dell'archivio interno per salvare i dati. Come per tutti gli archivi specifici dell'app, i file archiviati in questa directory vengono rimossi quando l'utente disinstalla l'app, anche se i file in questa directory potrebbero essere rimossi prima.
Per creare un file memorizzato nella cache, chiama
File.createTempFile():
Kotlin
File.createTempFile(filename, null, context.cacheDir)
Java
File.createTempFile(filename, null, context.getCacheDir());
La tua app accede a un file in questa directory utilizzando la
cacheDir proprietà di un
oggetto contesto e l'API File:
Kotlin
val cacheFile = File(context.cacheDir, filename)
Java
File cacheFile = new File(context.getCacheDir(), filename);
Rimuovere i file della cache
Anche se a volte Android elimina automaticamente i file della cache, non devi fare affidamento sul sistema per pulire questi file. Devi sempre gestire i file della cache dell'app all'interno dell'archivio interno.
Per rimuovere un file dalla directory della cache all'interno dell'archivio interno, utilizza uno dei seguenti metodi:
Il metodo
delete()su un oggettoFileche rappresenta il file:Kotlin
cacheFile.delete()
Java
cacheFile.delete();
Il
deleteFile()metodo del contesto dell'app, passando il nome del file:Kotlin
context.deleteFile(cacheFileName)
Java
context.deleteFile(cacheFileName);
Accesso dall'archivio esterno
Se l'archivio interno non fornisce spazio sufficiente per archiviare file specifici dell'app, valuta la possibilità di utilizzare l'archivio esterno. Il sistema fornisce directory all'interno dell' archivio esterno in cui un'app può organizzare i file che forniscono valore all'utente solo all'interno della tua app. Una directory è progettata per i file persistenti della tua app e un'altra contiene i file memorizzati nella cache della tua app.
Su Android 4.4 (livello API 19) o versioni successive, la tua app non deve richiedere alcuna autorizzazione relativa all'archivio per accedere alle directory specifiche dell'app all'interno dell'archivio esterno. I file archiviati in queste directory vengono rimossi quando l'app viene disinstallata.
Sui dispositivi con Android 9 (livello API 28) o versioni precedenti, la tua app può accedere ai file specifici dell'app appartenenti ad altre app, a condizione che disponga delle autorizzazioni di archiviazione appropriate. Per consentire agli utenti di avere un maggiore controllo sui propri file e per limitare l'ingombro dei file, alle app che hanno come target Android 10 (livello API 29) e versioni successive viene concesso per impostazione predefinita l'accesso con ambito all'archivio esterno, o archivio con ambito. Quando l'archivio con ambito è attivato, le app non possono accedere alle directory specifiche dell'app appartenenti ad altre app.
Verificare che l'archivio sia disponibile
Poiché l'archivio esterno si trova su un volume fisico che l'utente potrebbe essere in grado di rimuovere, verifica che il volume sia accessibile prima di provare a leggere o scrivere dati specifici dell'app nell'archivio esterno.
Puoi eseguire una query sullo stato del volume chiamando
Environment.getExternalStorageState().
Se lo stato restituito è
MEDIA_MOUNTED, allora
puoi leggere e scrivere file specifici dell'app all'interno dell'archivio esterno. Se è
MEDIA_MOUNTED_READ_ONLY,
puoi solo leggere questi file.
Ad esempio, i seguenti metodi sono utili per determinare la disponibilità dell'archivio:
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); }
Sui dispositivi senza archivio esterno rimovibile, utilizza il seguente comando per attivare un volume virtuale per testare la logica di disponibilità dell'archivio esterno:
adb shell sm set-virtual-disk true
Selezionare una posizione di archiviazione fisica
A volte, un dispositivo che alloca una partizione della memoria interna come archivio esterno fornisce anche uno slot per schede SD. Ciò significa che il dispositivo ha più volumi fisici che potrebbero contenere l'archivio esterno, quindi devi selezionare quello da utilizzare per l'archivio specifico dell'app.
Per accedere alle diverse posizioni, chiama
ContextCompat.getExternalFilesDirs().
Come mostrato nello snippet di codice, il primo elemento dell'array restituito è
considerato il volume di archiviazione esterno principale. Utilizza questo volume a meno che non sia pieno
o non disponibile.
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];
Accedere ai file persistenti
Per accedere ai file specifici dell'app dall'archivio esterno, chiama
getExternalFilesDir().
Per contribuire a mantenere le prestazioni dell'app, non aprire e chiudere lo stesso file più volte.
Il seguente snippet di codice mostra come chiamare getExternalFilesDir():
Kotlin
val appSpecificExternalDir = File(context.getExternalFilesDir(null), filename)
Java
File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);
Creare file della cache
Per aggiungere un file specifico dell'app alla cache all'interno dell'archivio esterno, ottieni un
riferimento a
externalCacheDir:
Kotlin
val externalCacheFile = File(context.externalCacheDir, filename)
Java
File externalCacheFile = new File(context.getExternalCacheDir(), filename);
Rimuovere i file della cache
Per rimuovere un file dalla directory della cache esterna, utilizza il
delete() metodo su un oggetto File che
rappresenta il file:
Kotlin
externalCacheFile.delete()
Java
externalCacheFile.delete();
Contenuti multimediali
Se la tua app funziona con file multimediali che forniscono valore all'utente solo all'interno della tua app, è consigliabile archiviarli in directory specifiche dell'app all'interno dell'archivio esterno, come mostrato nel seguente snippet di codice:
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; }
È importante utilizzare i nomi delle directory forniti dalle costanti API come
DIRECTORY_PICTURES.
Questi nomi di directory assicurano che i file vengano trattati correttamente dal sistema.
Se nessuno dei nomi delle sottodirectory predefiniti è adatto ai tuoi file, puoi
invece passare null a getExternalFilesDir(). Viene restituita la directory principale
specifica dell'app all'interno dell'archivio esterno.
Eseguire una query sullo spazio libero
Molti utenti non hanno molto spazio di archiviazione disponibile sui propri dispositivi, quindi la tua app deve utilizzare lo spazio con attenzione.
Se sai in anticipo la quantità di dati che stai archiviando, puoi scoprire la quantità di spazio che il dispositivo può fornire alla tua app chiamando
getAllocatableBytes().
Il valore restituito di getAllocatableBytes() potrebbe essere maggiore della attuale
quantità di spazio libero sul dispositivo. Questo perché il sistema ha identificato
i file che può rimuovere dalle directory della cache di altre app.
Se c'è spazio sufficiente per salvare i dati dell'app, chiama
allocateBytes().
In caso contrario, la tua app può chiedere all'utente di rimuovere alcuni
file dal dispositivo o rimuovere tutti i file della cache
dal dispositivo.
Il seguente snippet di codice mostra un esempio di come la tua app può eseguire una query sullo spazio libero sul dispositivo:
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); }
Creare un'attività di gestione dell'archivio
La tua app può dichiarare e creare un'attività personalizzata che, una volta avviata, consente
all'utente di gestire i dati che la tua app ha archiviato sul dispositivo dell'utente. Dichiari questa attività personalizzata di "gestione dello spazio" utilizzando l'
android:manageSpaceActivity
attributo nel file manifest. Le app di gestione file possono richiamare questa
attività
anche quando la tua app non la esporta, ovvero quando la tua attività imposta
android:exported su
false.
Chiedere all'utente di rimuovere alcuni file del dispositivo
Per richiedere all'utente di scegliere i file da rimuovere sul dispositivo, richiama un intent
che include l'
ACTION_MANAGE_STORAGE
azione. Questo intent mostra un messaggio all'utente. Se vuoi, questo messaggio può
mostrare la quantità di spazio libero disponibile sul dispositivo. Per mostrare queste
informazioni di facile utilizzo, utilizza il risultato del seguente calcolo:
StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()
Chiedere all'utente di rimuovere tutti i file della cache
In alternativa, puoi chiedere all'utente di cancellare i file della cache da tutte
le app sul dispositivo. Per farlo, richiama un intent che include l'
ACTION_CLEAR_APP_CACHE
azione dell'intent.
Risorse aggiuntive
Per ulteriori informazioni sul salvataggio dei file nell'archivio del dispositivo, consulta le seguenti risorse.