Skip to content Skip to sidebar Skip to footer

How To Download File In Android Using Retrofit Library?

I need to download all types of file (binary, image, text, etc) using Retrofit library in my app. All the examples on the net is using HTML GET method. I need to use POST to preven

Solution 1:

In kotlin, Do this:

In your service add method:

@Streaming@GET
    suspend fun downloadFile(@UrlfileUrl:String): Response<ResponseBody>

To call this method, from ViewModel:

viewModelScope.launch {
     val responseBody=yourServiceInstance.downloadFile(url).body()
     saveFile(responseBody,pathWhereYouWantToSaveFile)
}

To save file:

funsaveFile(body: ResponseBody?, pathWhereYouWantToSaveFile: String):String{
        if (body==null)
            return""var input: InputStream? = nulltry {
            input = body.byteStream()
            //val file = File(getCacheDir(), "cacheFileAppeal.srl")val fos = FileOutputStream(pathWhereYouWantToSaveFile)
            fos.use { output ->
                val buffer = ByteArray(4 * 1024) // or other buffer sizevar read: Intwhile (input.read(buffer).also { read = it } != -1) {
                    output.write(buffer, 0, read)
                }
                output.flush()
            }
            return pathWhereYouWantToSaveFile
        }catch (e:Exception){
            Log.e("saveFile",e.toString())
        }
        finally {
            input?.close()
        }
        return""
    }

Note:

  1. Make sure your refrofit client's base url and the url passed to downloadFile makes valid file url:

Retrofit's Base url + downloadFile's method url = File url

  1. Here I am using suspend keyword before downloadFile to call this from ViewModel, I have used viewModelScope.launch {} you can use different coroutine scope according to your caller end.

  2. Now pathWhereYouWantToSaveFile, If you want to store file into project's file directory, you can do this:

val fileName=url.substring(url.lastIndexOf("/")+1)
val pathWhereYouWantToSaveFile = myApplication.filesDir.absolutePath+fileName
  1. If you are storing the downloaded file under file or cache directory, you don't need to acquire permission, otherwise for public storage, you know the process.

Solution 2:

Use @Streaming

Asynchronous

EDIT 1

//On your api interface@POST("path/to/your/resource")@StreamingvoidapiRequest(Callback<POJO> callback);

restAdapter.apiRequest(newCallback<POJO>() {
        @Overridepublicvoidsuccess(POJO pojo, Response response) {
            try {
                //you can now get your file in the InputStreamInputStreamis= response.getBody().in();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Overridepublicvoidfailure(RetrofitError error) {

        }
    });

Synchronous

//On your api interface@POST("path/to/your/resource")@Streaming
Response apiRequest();

Responseresponse= restAdapter.apiRequest();

try {
    //you can now get your file in the InputStreamInputStreamis= response.getBody().in();
} catch (IOException e) {
    e.printStackTrace();
}

Solution 3:

This is How to DOWNLOAD file in Retrofit 2

publicinterfaceServerAPI {
        @GET
        Call<ResponseBody> downlload(@Url String fileUrl);

        Retrofitretrofit=newRetrofit.Builder()
                        .baseUrl("http://192.168.43.135/retro/") // REMEMBER TO END with /
                        .addConverterFactory(GsonConverterFactory.create())
                 .build();

}

    //How To Callpublicvoiddownload(){
        ServerAPIapi= ServerAPI.retrofit.create(ServerAPI.class);
        api.downlload("http://192.168.43.135/retro/pic.jpg").enqueue(newCallback<ResponseBody>() {
                    @OverridepublicvoidonResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        try {
                            Filepath= Environment.getExternalStorageDirectory();
                            Filefile=newFile(path, "file_name.jpg");
                            FileOutputStreamfileOutputStream=newFileOutputStream(file);
                            IOUtils.write(response.body().bytes(), fileOutputStream);
                        }
                        catch (Exception ex){
                        }
                    }

                    @OverridepublicvoidonFailure(Call<ResponseBody> call, Throwable t) {
                    }
                });
}

Solution 4:

If you use Retrofit 2.0.0, you can refer my answer under the question -- Use retrofit to download image file.

The key point is use okhttp3.ReponseBody to receive the raw binary data, not any POJO.

And you want to use POST method to get the file, it's easy, just change @GET to @POST, but it depend whether your server support the POST method!

Solution 5:

You can use below code for downloading with progress (Kotlin)

Retrofit Api Service

@Streaming@GET
fun downloadFile(@UrlfileUrl: String): Observable<Response<ResponseBody>>

make sure you add @Streaming for large file downloading

And paste below code in your Activity or Fragment

fundownloadfileFromRetrofit() {
    val retrofit = Retrofit.Builder()
        .baseUrl("ENTER_YOUR_BASE_URL")
        .client(OkHttpClient.Builder().build())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()
    val downloadService = retrofit.create(RetrofitApi::class.java)

   downloadService.downloadFile("FILE_URL_PATH").observeOn(AndroidSchedulers.mainThread())
        .subscribeOn(Schedulers.io()).subscribe({
            val task = object : AsyncTask<Void, Integer, Void>() {
                overridefundoInBackground(vararg voids: Void): Void? {
                    val writtenToDisk =writeResponseBodyToDisk(it.body()!!)
                    println("file download was a success? $writtenToDisk")
                    returnnull
                }
            }
            task.execute()
        }, {
            print(it.message)
        })
}

below is the writeResponseBodyToDisk method

funwriteResponseBodyToDisk(body: ResponseBody): Boolean {
    val appDirectoryName = "YOUR_DIRECTORY_NAME"val filename = "YOUR_FILE_NAME"val apkFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename)
    try {

        var inputStream: InputStream? = nullvar outputStream: OutputStream? = nulltry {
            val fileReader = ByteArray(4096)
            val fileSize = body.contentLength()
            var fileSizeDownloaded: Long = 0
            inputStream = body.byteStream()
            outputStream = FileOutputStream(apkFile)
            while (true) {
                val read = inputStream!!.read(fileReader)
                if (read == -1) {
                    break
                }
                outputStream.write(fileReader, 0, read)
                fileSizeDownloaded += read.toLong()

           calulateProgress(fileSize.toDouble(),fileSizeDownloaded.toDouble()
                println("file downloading $fileSizeDownloaded of $fileSize")

            outputStream.flush()

            returntrue
        } catch (e: Exception) {
            println(e.toString())
            returnfalse
        } finally {
            if (inputStream != null) {
                inputStream!!.close()
            }
            outputStream?.close()
        }
    } catch (e: Exception) {
        println(e.toString())
        returnfalse
    }

}

below method is for calculate progress

funcalulateProgress(totalSize:Double,downloadSize:Double):Double{
    return ((downloadSize/totalSize)*100)
}

Post a Comment for "How To Download File In Android Using Retrofit Library?"