Downloading a PDF file using Retrofit and Kotlin coroutines in an Android application involves setting up Retrofit to handle file downloads and using coroutines to manage asynchronous operations. Here's a step-by-step guide on how to achieve this:
Step 1: Set up Retrofit Interface for File Download
First, define your Retrofit interface to handle the file download:
interface FileDownloadService { @GET @Streaming suspend fun downloadFile(@Url fileUrl: String): ResponseBody}
@GET
: Specifies the HTTP method as GET.@Streaming
: Indicates that the response body should be streamed directly without buffering in memory, which is crucial for handling large files like PDFs efficiently.@Url
: Annotation for specifying the complete URL dynamically.
Step 2: Configure Retrofit Client
Set up your Retrofit client in a singleton object or as needed:
object RetrofitClient { private const val BASE_URL = "https://your_base_url_here.com/" private val okHttpClient = OkHttpClient.Builder() .build() private val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() fun createFileDownloadService(): FileDownloadService { return retrofit.create(FileDownloadService::class.java) }}
Ensure you have added necessary dependencies in your build.gradle
file:
implementation 'com.squareup.retrofit2:retrofit:2.9.0'implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Replace with your preferred converterimplementation 'com.squareup.okhttp3:okhttp:4.9.2'
Step 3: Implement Coroutine Function for File Download
Now, implement a coroutine function to handle the file download using Retrofit and coroutines:
suspend fun downloadFile(fileUrl: String, fileName: String): Boolean { val service = RetrofitClient.createFileDownloadService() return withContext(Dispatchers.IO) { try { val response = service.downloadFile(fileUrl) if (response.isSuccessful) { val downloadedFile = response.body() saveFileToStorage(downloadedFile, fileName) return@withContext true } else { // Handle unsuccessful response return@withContext false } } catch (e: Exception) { // Handle exception e.printStackTrace() return@withContext false } }}private suspend fun saveFileToStorage(body: ResponseBody?, fileName: String) { body?.let { try { val inputStream = it.byteStream() val file = File(context.getExternalFilesDir(null), fileName) FileOutputStream(file).use { outputStream -> inputStream.copyTo(outputStream) } } catch (e: Exception) { e.printStackTrace() } }}
Step 4: Call the Coroutine Function from your Activity or Fragment
Invoke the downloadFile()
function from your UI component (Activity or Fragment) within a coroutine scope:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Example usage CoroutineScope(Dispatchers.Main).launch { val fileUrl = "https://example.com/path/to/file.pdf" val fileName = "example_file.pdf" val downloadSuccess = downloadFile(fileUrl, fileName) if (downloadSuccess) { Toast.makeText(this@MainActivity, "File downloaded successfully", Toast.LENGTH_SHORT).show() // Handle file download success } else { Toast.makeText(this@MainActivity, "Failed to download file", Toast.LENGTH_SHORT).show() // Handle file download failure } } }}
Explanation:
- FileDownloadService: Retrofit interface defining the HTTP GET method for downloading files.
- RetrofitClient: Singleton object to configure and create Retrofit instances.
- downloadFile(): Coroutine function that uses Retrofit to initiate the file download and saves it to the external storage using
saveFileToStorage()
. - saveFileToStorage(): Helper function to save the downloaded file (
ResponseBody
) to the external storage. - MainActivity: Example of how to call
downloadFile()
within a coroutine scope (CoroutineScope
) and handle success or failure.
Permissions
Don't forget to add the necessary permissions in your AndroidManifest.xml
to write to external storage:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Note
- Error Handling: Implement appropriate error handling and exception handling in
downloadFile()
andsaveFileToStorage()
based on your application's requirements. - UI Thread: Perform UI-related operations (like showing Toasts) in the UI thread (
Dispatchers.Main
), and move long-running tasks toDispatchers.IO
.
By following these steps, you can successfully download a PDF file using Retrofit and Kotlin coroutines in your Android application, ensuring efficient handling of large files and smooth user experience. Adjust the code as per your specific requirements and error handling scenarios.
Examples
Android Retrofit Kotlin coroutines download PDF file example?
- Description: Example of using Retrofit with Kotlin coroutines to download a PDF file from a server.
- Code:
interface ApiService { @GET("download/pdf") @Streaming suspend fun downloadPdf(): ResponseBody}class PdfDownloadActivity : AppCompatActivity() { private val apiService: ApiService by lazy { Retrofit.Builder() .baseUrl("https://example.com/api/") .addConverterFactory(ScalarsConverterFactory.create()) .build() .create(ApiService::class.java) } private fun downloadPdfFile() { val downloadRequest = apiService.downloadPdf() GlobalScope.launch(Dispatchers.IO) { try { val response = downloadRequest.execute() if (response.isSuccessful) { val pdfFile = response.body() savePdfToFile(pdfFile) } else { // Handle error } } catch (e: Exception) { // Handle exception } } } private suspend fun savePdfToFile(pdfFile: ResponseBody?) { withContext(Dispatchers.IO) { pdfFile?.let { val inputStream = it.byteStream() val file = File(getExternalFilesDir(null), "example.pdf") file.outputStream().use { output -> inputStream?.copyTo(output) output.flush() } // Optionally show a notification or open the PDF file } } }}
This Kotlin code demonstrates using Retrofit to download a PDF file asynchronously with coroutines. The
downloadPdf()
function inApiService
defines the endpoint, andsavePdfToFile()
saves the downloaded file.Android Kotlin coroutine Retrofit download PDF to internal storage?
- Description: Kotlin code example to download a PDF file using Retrofit and save it to internal storage.
- Code:
interface ApiService { @GET("download/pdf") @Streaming suspend fun downloadPdf(): ResponseBody}class PdfDownloadActivity : AppCompatActivity() { private val apiService: ApiService by lazy { Retrofit.Builder() .baseUrl("https://example.com/api/") .addConverterFactory(ScalarsConverterFactory.create()) .build() .create(ApiService::class.java) } private fun downloadPdfFile() { GlobalScope.launch(Dispatchers.Main) { try { val response = apiService.downloadPdf() if (response.isSuccessful) { val pdfFile = response.body() savePdfToFile(pdfFile) } else { // Handle error } } catch (e: Exception) { // Handle exception } } } private suspend fun savePdfToFile(pdfFile: ResponseBody?) { withContext(Dispatchers.IO) { pdfFile?.let { val inputStream = it.byteStream() val file = File(filesDir, "example.pdf") file.outputStream().use { output -> inputStream?.copyTo(output) output.flush() } // Optionally show a notification or open the PDF file } } }}
This code is similar to the previous example but saves the downloaded PDF file to internal storage (
filesDir
).Kotlin coroutine Retrofit download PDF and show progress in Android?
- Description: Example of downloading a PDF file using Retrofit with coroutines and showing download progress in an Android app.
- Code:
interface ApiService { @GET("download/pdf") @Streaming suspend fun downloadPdf(): ResponseBody}class PdfDownloadActivity : AppCompatActivity() { private val apiService: ApiService by lazy { Retrofit.Builder() .baseUrl("https://example.com/api/") .addConverterFactory(ScalarsConverterFactory.create()) .build() .create(ApiService::class.java) } private fun downloadPdfFile() { val downloadRequest = apiService.downloadPdf() GlobalScope.launch(Dispatchers.IO) { try { val response = downloadRequest.execute() if (response.isSuccessful) { val pdfFile = response.body() savePdfToFile(pdfFile) } else { // Handle error } } catch (e: Exception) { // Handle exception } } } private suspend fun savePdfToFile(pdfFile: ResponseBody?) { withContext(Dispatchers.IO) { pdfFile?.let { val inputStream = it.byteStream() val file = File(getExternalFilesDir(null), "example.pdf") val totalFileSize = it.contentLength() var downloadedFileSize: Long = 0 val outputStream = file.outputStream() val buffer = ByteArray(4 * 1024) var bytesRead: Int while (inputStream.read(buffer).also { bytesRead = it } != -1) { outputStream.write(buffer, 0, bytesRead) downloadedFileSize += bytesRead // Optionally update progress bar or UI with progress } outputStream.flush() outputStream.close() inputStream.close() // Optionally show a notification or open the PDF file } } }}
This code adds a progress indicator while downloading the PDF file using Retrofit and coroutines. It reads the input stream in chunks and updates the progress as bytes are read.
Kotlin coroutine Retrofit download PDF with error handling?
- Description: Example of downloading a PDF file using Retrofit with Kotlin coroutines and handling errors.
- Code:
interface ApiService { @GET("download/pdf") @Streaming suspend fun downloadPdf(): ResponseBody}class PdfDownloadActivity : AppCompatActivity() { private val apiService: ApiService by lazy { Retrofit.Builder() .baseUrl("https://example.com/api/") .addConverterFactory(ScalarsConverterFactory.create()) .build() .create(ApiService::class.java) } private fun downloadPdfFile() { GlobalScope.launch(Dispatchers.Main) { try { val response = apiService.downloadPdf() if (response.isSuccessful) { val pdfFile = response.body() savePdfToFile(pdfFile) } else { // Handle HTTP error Log.e("PdfDownloadActivity", "HTTP error: ${response.code()}") } } catch (e: Exception) { // Handle network or coroutine exception Log.e("PdfDownloadActivity", "Error: ${e.message}") } } } private suspend fun savePdfToFile(pdfFile: ResponseBody?) { withContext(Dispatchers.IO) { pdfFile?.let { val inputStream = it.byteStream() val file = File(getExternalFilesDir(null), "example.pdf") file.outputStream().use { output -> inputStream?.copyTo(output) output.flush() } // Optionally show a notification or open the PDF file } } }}
This code includes error handling for HTTP errors and exceptions during the PDF file download process.
Retrofit download PDF with authentication using Kotlin coroutines?
- Description: Example of downloading a PDF file with authentication using Retrofit and Kotlin coroutines.
- Code:
interface ApiService { @GET("download/pdf") @Streaming suspend fun downloadPdf( @Header("Authorization") authToken: String ): ResponseBody}class PdfDownloadActivity : AppCompatActivity() { private val apiService: ApiService by lazy { Retrofit.Builder() .baseUrl("https://example.com/api/") .addConverterFactory(ScalarsConverterFactory.create()) .build() .create(ApiService::class.java) } private fun downloadPdfFile(authToken: String) { GlobalScope.launch(Dispatchers.Main) { try { val response = apiService.downloadPdf("Bearer $authToken") if (response.isSuccessful) { val pdfFile = response.body() savePdfToFile(pdfFile) } else { // Handle HTTP error Log.e("PdfDownloadActivity", "HTTP error: ${response.code()}") } } catch (e: Exception) { // Handle network or coroutine exception Log.e("PdfDownloadActivity", "Error: ${e.message}") } } } private suspend fun savePdfToFile(pdfFile: ResponseBody?) { withContext(Dispatchers.IO) { pdfFile?.let { val inputStream = it.byteStream() val file = File(getExternalFilesDir(null), "example.pdf") file.outputStream().use { output -> inputStream?.copyTo(output) output.flush() } // Optionally show a notification or open the PDF file } } }}
This code demonstrates downloading a PDF file with authentication using a Bearer token passed as a header in the Retrofit request.
More Tags
databaseselenium-ideamazon-redshiftc#-3.0azure-redis-cachetls1.2php-carbonvisual-studio-2015file-sharingdata-extraction
More Programming Questions
- C++ Pointer to Structure
- PostgreSQL - Removing Temporary Table
- HTML comments
- MySQL AUTO_INCREMENT: Primary Key Auto-increment
- Access memory address in python
- Make TextBox uneditable in Winforms/WPF
- How to specify method return type list of (what) in Python?
- How to Maximize Code Reuse in this Interface vs Inheritance C# Example
- Ensuring py.test includes the application directory in sys.path