3 Haziran 2020

2 Farklı Şekilde Dosya Kaydetme [Kotlin]

ile umut

Dosyalarımızı cache, internal ve external olarak kaydedebilirsiniz. Bunlarda public ve private olarak değişmektedir. Yani eğer kullanıcının görebilmesini istiyorsanız farklı bir işlem yapmanız gerekir. Bunun hakkında daha sonra bir makale yazacağım. Burada cache ve uygulama katmanı içerisine dosya kaydetmeyi anlatacağım. Bu iki katmana da kullanıcı ulaşamamaktadır. Ancak developer dosya yolunu tutarak veya kaydederek bunu kullanıcıya gösterebilir.

Cache Webden dosyamızı alabilmek için retrofit’i ve kotlin coroutines ile de iki extension function yazarak çok kolay bir şekilde dosya kaydetme işlemini eğer indirmemişse indirip, eğer daha önce indirmişse indirdiği yerden okuyarak çok hızlı ve tek satırda halledebilirsiniz. Fonksiyonun sonunda yer alan unit tipinde action parametresi ile de lambda olarak kaydedilen dosyamızı geri döndürerek işlem yapabiliriz.

Cache içerisine kaydedilen dosyalar android zorunlu hallerde yani hafıza gerektiği durumlarda uygulamaların cachelerini silebilmektedir. Dolayısıyla cache’e kaydetme işlemini yalnızca az kullanılan durumlarda yapmanın faydası var. Örneğin kullanıcı uygulamaya kayıt olurken gösterilen gizlilik politikaları gibi.

Şimdi geçelim kaydetme işlemlerimize…

Dosya Kaydetme metodumuzu Retrofit ile çağırma

Service.apiInterface.getFile(token, fileType).saveFile("${fileType}.pdf") {
                    pdfView.fromFile(it).load()
                }

Burada retrofit ile yazmış olduğumuz interface’imize bağlanıp metodumuzu çağırıp sonrasında aşağıda yazdığımız extension fonksiyonumuz ile saveFile diyerek dosyamızı kaydetme yapabilir ve okuyabilir hale getirebiliriz.

Kotlin extension function olarak yazmış olduğumuz saveFile fonksiyonumuzun içerisinde coroutines kullanarak globalscope yöntemiyle asenkron olarak çalışmasını sağlıyoruz.

Coroutines ile Cache’e kaydetme ve okuma

External Files Dir içerisine kaydetme

Cache yerine elbette dışarıya da kaydedebilirsiniz. Ben gereksiz tekrar tekrar kullanılmayacak dosyalar için basit ve gereksiz uygulamada alan kaplamaması durumları için gerekli durumlar için cache’e dosya kaydetmeyi anlatacağım. İsterseniz 13. satır yerine

val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.path
file = File("$storageDir/$fileNameWithExt")

ile değiştirerek uygulama katmanı içerine de kaydedip kullanabilirsiniz ancak o zaman da 4. satırdaki daha önceden kayıtlı mı sorgusunu da değiştirmeniz gerekir. Kısacası şöyle olacaktır.

private fun Call<ResponseBody>.saveFile(fileNameWithExt: String, action: (file: File?) -> Unit) {
        GlobalScope.launch {
            try {
                val storageDir = baseContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.path
                val file = File("$storageDir/$fileNameWithExt")
                if(file.exists()){
                    action(file)
                }else{
                    withContext(Dispatchers.IO) {
                        val response = [email protected]()
                        val buffer = response.body()?.byteStream()
                        var file: File? = null
                        if (buffer != null) {
                            file = File.createTempFile(fileNameWithExt, null, baseContext?.cacheDir)
                            if (file != null) {
                                buffer.copyStreamToFile(file)
                            }
                        }
                        action(file)
                    }
                }
            } catch (e: Exception) {
                Log.e("error", e.message ?: "")
            }
        }
    }

    private fun InputStream.copyStreamToFile(outputFile: File) {
        this.use { input ->
            val outputStream = FileOutputStream(outputFile)
            outputStream.use { output ->
                val buffer = ByteArray(4 * 1024)
                while (true) {
                    val byteCount = input.read(buffer)
                    if (byteCount < 0) break
                    output.write(buffer, 0, byteCount)
                }
                output.flush()
            }

        }
    }