In molti casi, l'app crea file a cui altre app non hanno bisogno o non devono accedere. Il sistema fornisce le seguenti posizioni per l'archiviazione di questi file specifici dell'app:
Directory di archiviazione interna: queste directory includono una posizione dedicata per l'archiviazione dei file permanenti e un'altra per l'archiviazione dei dati della cache. Il sistema impedisce ad altre app di accedere a queste posizioni, che vengono criptate su Android 10 (livello API 29) e versioni successive. Queste caratteristiche rendono queste posizioni un'ottima posizione per archiviare dati sensibili a cui può accedere solo la tua app.
Directory di archiviazione esterna:queste directory includono una posizione dedicata per l'archiviazione dei file permanenti e un'altra per l'archiviazione dei dati della cache. Sebbene un'altra app possa accedere a queste directory, se dispone delle autorizzazioni appropriate, i file archiviati in queste directory sono pensati per essere utilizzati solo dalla tua app. Se intendi creare file a cui altre app dovrebbero poter accedere, l'app deve archiviare questi file nella parte dell'archivio condiviso dell'unità di archiviazione esterna.
Quando l'utente disinstalla la tua app, i file salvati nello spazio di archiviazione specifico dell'app vengono rimossi. Per questo motivo, non devi utilizzare questo spazio di archiviazione per salvare tutto ciò che l'utente si aspetta di rimanere indipendentemente dalla tua app. Ad esempio, se la tua app consente agli utenti di acquisire foto, l'utente si aspetta di poter accedere a queste foto anche dopo la disinstallazione dell'app. Pertanto, ti consigliamo di utilizzare lo spazio di archiviazione condiviso per salvare questi tipi di file nella raccolta multimediale appropriata.
Le seguenti sezioni descrivono come archiviare i file e accedervi all'interno di directory specifiche dell'app.
Accesso dalla memoria interna
Per ogni app, il sistema fornisce directory all'interno della memoria interna in cui l'app può organizzare i propri file. Una directory è progettata per i file permanenti dell'app, mentre un'altra contiene i file memorizzati nella cache dell'app. L'app non richiede alcuna autorizzazione di sistema per leggere e scrivere sui file in queste directory.
Altre app non possono accedere ai file archiviati nella memoria interna. Ciò rende l'archiviazione interna una buona posizione per i dati delle app a cui altre app non dovrebbero accedere.
Tuttavia, tieni presente che queste directory tendono a essere di dimensioni ridotte. Prima di scrivere file specifici dell'app nella memoria interna, l'app deve eseguire una query sullo spazio libero sul dispositivo.
Accedere ai file permanenti
I file ordinari e permanenti della tua app risiedono in una directory a cui puoi accedere utilizzando la proprietà filesDir
di un oggetto di contesto. Il framework offre diversi metodi per accedere ai file e archiviarli in questa directory.
Accedere ai file e archiviarli
Puoi utilizzare l'API File
per accedere ai file e archiviarli.
Per 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 una FileOutputStream
che scriva
in un file all'interno della directory filesDir
.
Il seguente snippet di codice mostra come scrivere 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 memorizzati in questa directory all'interno della memoria interna, utilizza un elemento 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(); }
Visualizza l'elenco di file
Puoi ottenere un array contenente i nomi di tutti i file all'interno della directory filesDir
chiamando fileList()
, come mostrato nel seguente snippet di codice:
Kotlin
var files: Array<String> = context.fileList()
Java
Array<String> files = context.fileList();
Crea directory nidificate
Puoi anche creare directory nidificate o aprire una directory interna, chiamando getDir()
nel codice basato su Kotlin o passando la directory radice e un nuovo nome della directory in 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 hai bisogno di archiviare i dati sensibili solo temporaneamente, utilizza la directory della cache designata dell'app all'interno della memoria interna per salvare i dati. Come per tutto lo spazio di archiviazione specifico per le 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());
L'app accede a un file in questa directory utilizzando la proprietà cacheDir
di un oggetto di 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 i file della cache autonomamente, non dovresti fare affidamento sul sistema per ripulirli. Devi sempre conservare i file della cache dell'app nella memoria interna.
Per rimuovere un file dalla directory della cache all'interno della memoria interna, utilizza uno dei seguenti metodi:
Il metodo
delete()
su un oggettoFile
che rappresenta il file:Kotlin
cacheFile.delete()
Java
cacheFile.delete();
Il metodo
deleteFile()
del contesto dell'app, che trasmette il nome del file:Kotlin
context.deleteFile(cacheFileName)
Java
context.deleteFile(cacheFileName);
Accesso da unità di archiviazione esterna
Se la memoria interna non offre spazio sufficiente per archiviare file specifici dell'app, valuta la possibilità di utilizzare invece una memoria esterna. Il sistema fornisce directory all'interno dell'unità di archiviazione esterna in cui un'app può organizzare file che forniscono valore all'utente solo all'interno dell'app. Una directory è progettata per i file permanenti dell'app, mentre un'altra contiene i file memorizzati nella cache dell'app.
Su Android 4.4 (livello API 19) o versioni successive, l'app non deve richiedere autorizzazioni relative allo spazio di archiviazione per accedere a directory specifiche dell'app all'interno dello spazio di archiviazione 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, l'app può accedere ai file specifici dell'app che appartengono ad altre app, purché quest'ultima disponga delle autorizzazioni di archiviazione appropriate. Per offrire agli utenti un maggiore controllo sui file e limitare il numero di file in eccesso, per impostazione predefinita alle app destinate ad Android 10 (livello API 29) e versioni successive viene concesso l'accesso con ambito all'archiviazione esterna, o archiviazione con ambito. Quando l'archiviazione con ambito è abilitata, le app non possono accedere alle directory specifiche delle app che appartengono ad altre app.
Verificare che lo spazio di archiviazione sia disponibile
Poiché l'unità di archiviazione esterna 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 nella memoria esterna.
Puoi eseguire query sullo stato del volume chiamando
Environment.getExternalStorageState()
.
Se lo stato restituito è MEDIA_MOUNTED
, puoi leggere e scrivere file specifici dell'app all'interno dell'unità di archiviazione esterna. Se è MEDIA_MOUNTED_READ_ONLY
, puoi solo leggere questi file.
Ad esempio, i seguenti metodi sono utili per determinare la disponibilità dello spazio di archiviazione:
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 unità di archiviazione esterna rimovibile, utilizza il seguente comando per abilitare un volume virtuale per testare la logica di disponibilità dell'unità di archiviazione esterna:
adb shell sm set-virtual-disk true
Seleziona una posizione di archiviazione fisica
A volte, un dispositivo che alloca una partizione della propria memoria interna come memoria esterna fornisce anche uno slot per schede SD. Ciò significa che il dispositivo ha più volumi fisici che potrebbero contenere unità di archiviazione esterna, quindi devi selezionare quale utilizzare per l'archiviazione specifica dell'app.
Per accedere alle varie sedi, chiama il numero
ContextCompat.getExternalFilesDirs()
.
Come mostrato nello snippet di codice, il primo elemento nell'array restituito viene considerato il volume di archiviazione esterna principale. Usa questo volume se non è 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 permanenti
Per accedere a file specifici dell'app da un'unità di archiviazione esterna, chiama
getExternalFilesDir()
.
Per 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'unità di archiviazione esterna, consulta 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 metodo delete()
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 dell'app, ti consigliamo di archiviarli in directory specifiche dell'app all'interno di spazio di archiviazione esterno, come illustrato 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 di directory forniti da costanti API come DIRECTORY_PICTURES
.
Questi nomi di directory assicurano che i file vengano trattati correttamente dal sistema.
Se nessuno dei nomi delle sottodirectory predefinite corrisponde ai tuoi file, puoi trasferire null
in getExternalFilesDir()
. Questo restituisce la directory principale specifica dell'app all'interno dell'unità di archiviazione esterna.
Esegui query sullo spazio libero
Molti utenti non hanno molto spazio di archiviazione a disposizione sui loro dispositivi, quindi la tua app dovrebbe occupare spazio in modo ponderato.
Se conosci in anticipo la quantità di dati che stai archiviando, puoi scoprire
quanto spazio il dispositivo può fornire alla tua app chiamando
getAllocatableBytes()
.
Il valore restituito di getAllocatableBytes()
potrebbe essere maggiore della quantità attuale di spazio libero sul dispositivo. Questo perché il sistema ha identificato dei file che può rimuovere dalle directory della cache di altre app.
Se c'è abbastanza spazio per salvare i dati della tua app, chiama
allocateBytes()
.
In caso contrario, l'app può richiedere 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 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 dello spazio di archiviazione
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 suo dispositivo. Puoi
dichiarare questa attività di "gestione dello spazio" personalizzata utilizzando l'attributo
android:manageSpaceActivity
nel file manifest. Le app di gestione dei file possono attivare questa
attività
anche se l'app non esporta l'attività, ovvero quando l'attività è impostata
android:exported
su
false
.
Chiedi all'utente di rimuovere alcuni file del dispositivo
Per richiedere all'utente di scegliere i file sul dispositivo da rimuovere, richiama un intent che include l'azione ACTION_MANAGE_STORAGE
. Questo intent mostra una richiesta all'utente. Se vuoi, questo messaggio può
mostrare la quantità di spazio libero disponibile sul dispositivo. Per mostrare queste informazioni facili da usare, utilizza il risultato del seguente calcolo:
StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()
Chiedi all'utente di rimuovere tutti i file della cache
In alternativa, puoi richiedere all'utente di cancellare i file della cache da tutte
le app sul dispositivo. Per farlo, richiama un intent che include l'azione dell'intent ACTION_CLEAR_APP_CACHE
.
Risorse aggiuntive
Per ulteriori informazioni sul salvataggio dei file nello spazio di archiviazione del dispositivo, consulta le risorse seguenti.