Uygulamanız çoğu durumda, diğer uygulamaların erişmesi gerekmeyen veya erişmemesi gereken dosyalar oluşturur. Sistem, bu tür uygulamaya özgü dosyaları depolamak için aşağıdaki konumları sağlar:
Dahili depolama alanı dizinleri: Bu dizinlerde hem kalıcı dosyaların depolanmasına özel bir konum hem de önbelleğe alınan verilerin depolanmasına özel başka bir konum bulunur. Sistem, diğer uygulamaların bu konumlara erişmesini engeller ve Android 10 (API düzeyi 29) ve sonraki sürümlerde bu konumlar şifrelenir. Bu özellikler, bu konumları yalnızca uygulamanızın erişebileceği hassas verileri depolamak için iyi bir yer haline getirir.
Harici depolama dizinleri: Bu dizinler hem kalıcı dosyaların depolanmasına yönelik özel bir konum hem de önbelleğe alınan verilerin depolanmasına yönelik başka bir konum içerir. Uygun izinlere sahip başka bir uygulamanın bu dizinlere erişmesi mümkün olsa da bu dizinlerde depolanan dosyalar yalnızca uygulamanız tarafından kullanılmak üzere tasarlanmıştır. Özellikle diğer uygulamaların erişebileceği dosyalar oluşturmak istiyorsanız uygulamanız bu dosyaları harici depolama alanının paylaşılan depolama bölümünde saklamalıdır.
Kullanıcı uygulamanızı kaldırdığında uygulamaya özel depolama alanına kaydedilen dosyalar kaldırılır. Bu davranış nedeniyle, kullanıcının uygulamanızdan bağımsız olarak kalmasını beklediği hiçbir şeyi kaydetmek için bu depolama alanını kullanmamalısınız. Örneğin, uygulamanız kullanıcıların fotoğraf çekmesine izin veriyorsa kullanıcı, uygulamanızı kaldırdıktan sonra bile bu fotoğraflara erişebileceğini bekler. Bu nedenle, bu tür dosyaları uygun medya koleksiyonuna kaydetmek için paylaşılan depolama alanını kullanmalısınız.
Aşağıdaki bölümlerde, uygulamaya özel dizinlerde dosyaların nasıl depolanacağı ve bu dosyalara nasıl erişileceği açıklanmaktadır.
Dahili depolama alanından erişim
Sistem, her uygulama için dahili depolama alanında uygulamanın dosyalarını düzenleyebileceği dizinler sağlar. Bir dizin uygulamanızın kalıcı dosyaları için tasarlanmıştır, diğeri ise uygulamanızın önbelleğe alınmış dosyalarını içerir. Uygulamanızın bu dizinlerdeki dosyaları okumak ve yazmak için sistem iznine ihtiyacı yoktur.
Diğer uygulamalar, dahili depolama alanında depolanan dosyalara erişemez. Bu nedenle, dahili depolama alanı diğer uygulamaların erişmemesi gereken uygulama verileri için iyi bir yerdir.
Ancak bu dizinlerin genellikle küçük olduğunu unutmayın. Uygulamanız, uygulamaya özel dosyaları dahili depolama alanına yazmadan önce cihazdaki boş alanı sorgulamalıdır.
Kalıcı dosyalara erişme
Uygulamanızın normal, kalıcı dosyaları, bir bağlam nesnesinin filesDir
mülkünü kullanarak erişebileceğiniz bir dizinde bulunur. Çerçeve, bu dizindeki dosyalara erişmenize ve dosya depolamanıza yardımcı olacak çeşitli yöntemler sunar.
Dosyalara erişme ve dosya depolama
Dosyalara erişmek ve dosya depolamak için File
API'yi kullanabilirsiniz.
Uygulamanızın performansını korumak için aynı dosyayı birden çok kez açıp kapatmayın.
Aşağıdaki kod snippet'inde, File
API'nin nasıl kullanılacağı gösterilmektedir:
Kotlin
val file = File(context.filesDir, filename)
Java
File file = new File(context.getFilesDir(), filename);
Akış kullanarak dosya depolama
File
API'yi kullanmanın alternatifi olarak, filesDir
dizininde bir dosyaya yazan bir FileOutputStream
almak için openFileOutput()
'i çağırabilirsiniz.
Aşağıdaki kod snippet'inde, bir dosyaya nasıl metin yazılacağını görebilirsiniz:
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()); }
Dahili depolama alanındaki bu dizinde depolanan dosyalara diğer uygulamaların erişmesine izin vermek için FLAG_GRANT_READ_URI_PERMISSION
özelliğine sahip bir FileProvider
kullanın.
Akış kullanarak bir dosyaya erişme
Bir dosyayı akış olarak okumak için openFileInput()
kullanın:
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(); }
Dosya listesini görüntüleme
Aşağıdaki kod snippet'inde gösterildiği gibi fileList()
işlevini çağırarak filesDir
dizinindeki tüm dosyaların adlarını içeren bir dizi alabilirsiniz:
Kotlin
var files: Array<String> = context.fileList()
Java
Array<String> files = context.fileList();
İç içe dizinler oluşturma
Kotlin tabanlı kodda getDir()
'i çağırarak veya Java tabanlı kodda kök dizini ve yeni bir dizin adını bir File
yapıcısına aktararak iç içe dizinler oluşturabilir ya da iç dizin açabilirsiniz:
Kotlin
context.getDir(dirName, Context.MODE_PRIVATE)
Java
File directory = context.getFilesDir(); File file = new File(directory, filename);
Önbellek dosyaları oluşturma
Hassas verileri yalnızca geçici olarak saklamanız gerekiyorsa verileri kaydetmek için uygulamanın dahili depolama alanındaki özel önbelleğe alma dizini kullanmanız gerekir. Uygulamaya özgü tüm depolama alanlarında olduğu gibi, bu dizinde depolanan dosyalar da kullanıcı uygulamanızı kaldırdığında kaldırılır. Ancak bu dizindeki dosyalar daha önce kaldırılabilir.
Önbelleğe alınmış bir dosya oluşturmak için File.createTempFile()
işlevini çağırın:
Kotlin
File.createTempFile(filename, null, context.cacheDir)
Java
File.createTempFile(filename, null, context.getCacheDir());
Uygulamanız, bağlam nesnesinin cacheDir
mülkünü ve File
API'yi kullanarak bu dizindeki bir dosyaya erişiyor:
Kotlin
val cacheFile = File(context.cacheDir, filename)
Java
File cacheFile = new File(context.getCacheDir(), filename);
Önbelleğe alınan dosyaları kaldırma
Android bazen önbellek dosyalarını kendi kendine silse de bu dosyaları sizin için temizlemesini beklememelisiniz. Uygulamanızın önbelleğe alınmış dosyalarını her zaman dahili depolama alanında tutmanız gerekir.
Bir dosyayı dahili depolama alanındaki önbellek dizininden kaldırmak için aşağıdaki yöntemlerden birini kullanın:
Dosyayı temsil eden
File
nesnesindedelete()
yöntemi:Kotlin
cacheFile.delete()
Java
cacheFile.delete();
Dosyanın adını ileten uygulama bağlamının
deleteFile()
yöntemi:Kotlin
context.deleteFile(cacheFileName)
Java
context.deleteFile(cacheFileName);
Harici depolama alanından erişim
Dahili depolama alanı, uygulamaya özgü dosyaları depolamak için yeterli alan sağlamıyorsa bunun yerine harici depolama alanı kullanabilirsiniz. Sistem, harici depolama alanında bir uygulamanın kullanıcıya değer sağlayan dosyaları yalnızca uygulamanızda düzenleyebileceği dizinler sağlar. Bir dizin uygulamanızın kalıcı dosyaları için tasarlanmıştır, diğeri ise uygulamanızın önbelleğe alınan dosyalarını içerir.
Android 4.4 (API düzeyi 19) veya sonraki sürümlerde, uygulamanızın harici depolama alanındaki uygulamaya özel dizinlere erişmek için depolama alanıyla ilgili izin istemesi gerekmez. Bu dizinlerde depolanan dosyalar, uygulamanızın yüklemesi kaldırıldığında kaldırılır.
Android 9 (API düzeyi 28) veya önceki sürümleri çalıştıran cihazlarda, uygulamanızın uygun depolama izinlerine sahip olması koşuluyla uygulamanız diğer uygulamalara ait uygulamaya özel dosyalara erişebilir. Kullanıcılara dosyaları üzerinde daha fazla kontrol vermek ve dosya karmaşasını sınırlandırmak için Android 10 (API düzeyi 29) ve sonraki sürümleri hedefleyen uygulamalara varsayılan olarak harici depolamaya veya kısıtlı depolamaya kapsamlı erişim verilir. Kapsamlı depolama alanı etkinleştirildiğinde uygulamalar, diğer uygulamalara ait uygulamaya özel dizinlere erişemez.
Depolama alanının kullanılabilir olduğunu doğrulama
Harici depolama alanı, kullanıcının kaldırabileceği fiziksel bir birimde bulunduğundan, harici depolama alanından uygulamaya özgü verileri okumaya veya uygulamaya özgü verileri harici depolama alanına yazmaya çalışmadan önce birime erişilebildiğini doğrulayın.
Environment.getExternalStorageState()
çağrısını yaparak ses düzeyinin durumunu sorgulayabilirsiniz.
Döndürülen durum MEDIA_MOUNTED
ise harici depolama alanında uygulamaya özgü dosyaları okuyabilir ve yazabilirsiniz. MEDIA_MOUNTED_READ_ONLY
ise bu dosyaları yalnızca okuyabilirsiniz.
Örneğin, depolama alanı kullanılabilirliğini belirlemek için aşağıdaki yöntemler faydalıdır:
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); }
Çıkarılabilir harici depolama alanı olmayan cihazlarda, harici depolama alanı kullanılabilirlik mantığınızı test etmek için sanal bir birim etkinleştirmek üzere aşağıdaki komutu kullanın:
adb shell sm set-virtual-disk true
Fiziksel depolama alanı seçin
Bazen dahili belleğinin bir bölümünü harici depolama alanı olarak ayıran cihazlarda SD kart yuvası da bulunur. Bu, cihazda harici depolama alanı içerebilecek birden fazla fiziksel birim bulunduğu anlamına gelir. Bu nedenle, uygulamaya özel depolama alanınız için hangisini kullanacağınızı seçmeniz gerekir.
Farklı konumlara erişmek için ContextCompat.getExternalFilesDirs()
tuşuna basın.
Kod snippet'inde gösterildiği gibi, döndürülen dizideki ilk öğe birincil harici depolama birimi olarak kabul edilir. Dolu veya kullanılamıyorsa bu depolama alanını kullanın.
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];
Kalıcı dosyalara erişme
Harici depolama alanındaki uygulamaya özel dosyalara erişmek için getExternalFilesDir()
işlevini çağırın.
Uygulamanızın performansını korumak için aynı dosyayı birden çok kez açıp kapatmayın.
Aşağıdaki kod snippet'inde, getExternalFilesDir()
işlevinin nasıl çağrılacağı gösterilmektedir:
Kotlin
val appSpecificExternalDir = File(context.getExternalFilesDir(null), filename)
Java
File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);
Önbellek dosyaları oluşturma
Harici depolama alanındaki önbelleğe uygulamaya özel bir dosya eklemek için externalCacheDir
referansı alın:
Kotlin
val externalCacheFile = File(context.externalCacheDir, filename)
Java
File externalCacheFile = new File(context.getExternalCacheDir(), filename);
Önbelleğe alınan dosyaları kaldırma
Bir dosyayı harici önbellek dizininden kaldırmak için dosyayı temsil eden bir File
nesnesinde delete()
yöntemini kullanın:
Kotlin
externalCacheFile.delete()
Java
externalCacheFile.delete();
Medya içeriği
Uygulamanız, kullanıcıya yalnızca uygulamanız içinde değer sağlayan medya dosyalarıyla çalışıyorsa bu dosyaları, aşağıdaki kod snippet'inde gösterildiği gibi harici depolama alanında uygulamaya özel dizinlerde depolamak en iyisidir:
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; }
DIRECTORY_PICTURES
gibi API sabitleri tarafından sağlanan dizin adlarını kullanmanız önemlidir.
Bu dizin adları, dosyaların sistem tarafından doğru şekilde işlenmesini sağlar.
Önceden tanımlanmış alt dizin adlarından hiçbiri dosyalarınıza uygun değilse bunun yerine null
değerini getExternalFilesDir()
değerine iletebilirsiniz. Bu komut, harici depolama alanındaki uygulamaya özel kök dizini döndürür.
Boş alanı sorgulayın
Birçok kullanıcının cihazlarında fazla depolama alanı olmadığından uygulamanız alanı dikkatli bir şekilde kullanmalıdır.
Ne kadar veri depolayacağınızı önceden biliyorsanız getAllocatableBytes()
çağrısını yaparak cihazın uygulamanıza ne kadar alan sağlayabileceğini öğrenebilirsiniz.
getAllocatableBytes()
işlevinin döndürdüğü değer, cihazdaki mevcut boş alan miktarından daha büyük olabilir. Bunun nedeni, sistemin diğer uygulamaların önbellek dizinlerinden kaldırabileceği dosyaları tespit etmiş olmasıdır.
Uygulamanızın verilerini kaydedecek yeterli alan varsa allocateBytes()
numaralı telefonu arayın.
Aksi takdirde uygulamanız kullanıcıdan cihazdan bazı dosyaları veya tüm önbellek dosyalarını kaldırmasını isteyebilir.
Aşağıdaki kod snippet'inde, uygulamanızın cihazdaki boş alanı nasıl sorgulayabileceğine dair bir örnek gösterilmektedir:
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); }
Depolama alanı yönetimi etkinliği oluşturma
Uygulamanız, başlatıldığında kullanıcının uygulamanızın cihazında depoladığı verileri yönetmesine olanak tanıyan özel bir etkinlik tanımlayıp oluşturabilir. Bu özel "alanı yönetme" etkinliğini, manifest dosyasında android:manageSpaceActivity
özelliğini kullanarak bildirirsiniz. Dosya yöneticisi uygulamaları, uygulamanız etkinliği dışa aktarmadığında bile bu etkinliği çağırabilir. Yani etkinliğiniz android:exported
değerini false
olarak ayarlar.
Kullanıcıdan bazı cihaz dosyalarını kaldırmasını isteme
Kullanıcıdan cihazdaki dosyaları seçmesini istemek için ACTION_MANAGE_STORAGE
işlemini içeren bir intent çağırın. Bu intent, kullanıcıya bir istem gösterir. İsterseniz bu istemde cihazda mevcut boş alan miktarı gösterilebilir. Bu kullanıcı dostu bilgileri göstermek için aşağıdaki hesaplamanın sonucunu kullanın:
StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()
Kullanıcıdan tüm önbellek dosyalarını kaldırmasını isteyin
Alternatif olarak, kullanıcıdan cihazdaki tüm uygulamalardaki önbelleğe alınmış dosyaları temizlemesini isteyebilirsiniz. Bunu yapmak için ACTION_CLEAR_APP_CACHE
intent işlemini içeren bir intent çağırın.
Ek kaynaklar
Dosyaları cihazın depolama alanına kaydetme hakkında daha fazla bilgi için aşağıdaki kaynaklara göz atın.