Elysia Tools
Navigation mobile
Kotlin
Exemples de Programmation Réseau Android Kotlin
Exemples de programmation réseau Android Kotlin incluant requêtes HTTP, téléchargement/téléversement de fichiers et connexions WebSocket
Exemples
Entrées de cette collection
Requêtes HTTP
Envoyer des requêtes GET et POST en utilisant HttpURLConnection et la bibliothèque OkHttp avec gestion appropriée des erreurs
Difficulté
6/10
Temps estimé
30 min
Étiquettes
kotlin, android, networking, http
Prérequis
Basic Kotlin knowledge, Internet permission in manifest
// Android Kotlin HTTP Request Examples
// Using HttpURLConnection and OkHttp
import android.content.Context
import kotlinx.coroutines.*
import java.io.*
import java.net.*
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
// 1. HttpURLConnection Examples
class HttpURLConnectionExample(private val context: Context) {
// Simple GET request
suspend fun simpleGetRequest(url: String): String? = withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
val urlObj = URL(url)
connection = urlObj.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 10000
connection.readTimeout = 10000
val responseCode = connection.responseCode
println("Response Code: $responseCode")
if (responseCode == HttpURLConnection.HTTP_OK) {
val response = connection.inputStream.bufferedReader().use { it.readText() }
println("Response: $response")
return@withContext response
} else {
println("Error response code: $responseCode")
return@withContext null
}
} catch (e: Exception) {
println("GET Request Error: ${e.message}")
return@withContext null
} finally {
connection?.disconnect()
}
}
// POST request with JSON body
suspend fun postJsonRequest(url: String, jsonData: JSONObject): String? = withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
val urlObj = URL(url)
connection = urlObj.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("Content-Type", "application/json")
connection.doOutput = true
// Write JSON body
val outputStream = connection.outputStream
outputStream.write(jsonData.toString().toByteArray(Charsets.UTF_8))
outputStream.flush()
outputStream.close()
val responseCode = connection.responseCode
println("POST Response Code: $responseCode")
if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED) {
val response = connection.inputStream.bufferedReader().use { it.readText() }
println("POST Response: $response")
return@withContext response
} else {
return@withContext null
}
} catch (e: Exception) {
println("POST Request Error: ${e.message}")
return@withContext null
} finally {
connection?.disconnect()
}
}
// POST request with form data
suspend fun postFormData(url: String, params: Map<String, String>): String? = withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
val urlObj = URL(url)
connection = urlObj.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
connection.doOutput = true
// Build form data
val formData = params.map { "${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}" }
.joinToString("&")
val outputStream = connection.outputStream
outputStream.write(formData.toByteArray(Charsets.UTF_8))
outputStream.flush()
outputStream.close()
val responseCode = connection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
val response = connection.inputStream.bufferedReader().use { it.readText() }
return@withContext response
} else {
return@withContext null
}
} catch (e: Exception) {
println("Form POST Error: ${e.message}")
return@withContext null
} finally {
connection?.disconnect()
}
}
// GET request with headers
suspend fun getRequestWithHeaders(url: String, headers: Map<String, String>): String? = withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
val urlObj = URL(url)
connection = urlObj.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
// Add custom headers
headers.forEach { (key, value) ->
connection.setRequestProperty(key, value)
}
val responseCode = connection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
val response = connection.inputStream.bufferedReader().use { it.readText() }
return@withContext response
} else {
return@withContext null
}
} catch (e: Exception) {
println("GET with Headers Error: ${e.message}")
return@withContext null
} finally {
connection?.disconnect()
}
}
}
// 2. OkHttp Examples
class OkHttpExample(private val context: Context) {
private val client = OkHttpClient.Builder()
.connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
.readTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
.build()
// Simple GET with OkHttp
suspend fun simpleGet(url: String): String? = withContext(Dispatchers.IO) {
try {
val request = Request.Builder()
.url(url)
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("OkHttp GET Error: ${e.message}")
return@withContext null
}
}
// Async GET with callback
fun asyncGet(url: String, callback: (String?) -> Unit) {
val request = Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
println("Async GET failed: ${e.message}")
callback(null)
}
override fun onResponse(call: Call, response: Response) {
val body = response.body?.string()
callback(body)
}
})
}
// POST with JSON body
suspend fun postJson(url: String, json: JSONObject): String? = withContext(Dispatchers.IO) {
try {
val mediaType = "application/json".toMediaType()
val body = json.toString().toRequestBody(mediaType)
val request = Request.Builder()
.url(url)
.post(body)
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("OkHttp POST Error: ${e.message}")
return@withContext null
}
}
// POST with form data
suspend fun postForm(url: String, params: Map<String, String>): String? = withContext(Dispatchers.IO) {
try {
val formBody = FormBody.Builder()
params.forEach { (key, value) ->
formBody.add(key, value)
}
val request = Request.Builder()
.url(url)
.post(formBody.build())
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("Form POST Error: ${e.message}")
return@withContext null
}
}
// PUT request
suspend fun putRequest(url: String, json: JSONObject): String? = withContext(Dispatchers.IO) {
try {
val mediaType = "application/json".toMediaType()
val body = json.toString().toRequestBody(mediaType)
val request = Request.Builder()
.url(url)
.put(body)
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("PUT Error: ${e.message}")
return@withContext null
}
}
// DELETE request
suspend fun deleteRequest(url: String): Boolean = withContext(Dispatchers.IO) {
try {
val request = Request.Builder()
.url(url)
.delete()
.build()
val response = client.newCall(request).execute()
return@withContext response.isSuccessful
} catch (e: Exception) {
println("DELETE Error: ${e.message}")
return@withContext false
}
}
// Request with custom headers
suspend fun requestWithHeaders(
url: String,
headers: Map<String, String>,
method: String = "GET"
): String? = withContext(Dispatchers.IO) {
try {
val requestBuilder = Request.Builder()
.url(url)
// Add headers
headers.forEach { (key, value) ->
requestBuilder.addHeader(key, value)
}
// Set method
when (method.uppercase()) {
"POST" -> {
val mediaType = "application/json".toMediaType()
val body = "{}".toRequestBody(mediaType)
requestBuilder.post(body)
}
"PUT" -> {
val mediaType = "application/json".toMediaType()
val body = "{}".toRequestBody(mediaType)
requestBuilder.put(body)
}
"DELETE" -> requestBuilder.delete()
}
val response = client.newCall(requestBuilder.build()).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("Request with Headers Error: ${e.message}")
return@withContext null
}
}
}
// 3. Advanced HTTP Operations
class AdvancedHttpExample(private val context: Context) {
private val client = OkHttpClient()
// Multipart upload
suspend fun uploadMultipart(
url: String,
file: File,
fileParamName: String = "file",
params: Map<String, String> = emptyMap()
): String? = withContext(Dispatchers.IO) {
try {
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
// Add parameters
params.forEach { (key, value) ->
requestBody.addFormDataPart(key, value)
}
// Add file
val mediaType = "multipart/form-data".toMediaType()
requestBody.addFormDataPart(
fileParamName,
file.name,
file.asRequestBody(mediaType)
)
val request = Request.Builder()
.url(url)
.post(requestBody.build())
.build()
val response = client.newCall(request).execute()
return@withContext response.body?.string()
} catch (e: Exception) {
println("Multipart Upload Error: ${e.message}")
return@withContext null
}
}
// Download file with progress
suspend fun downloadFileWithProgress(
url: String,
outputFile: File,
onProgress: (Long, Long) -> Unit
): Boolean = withContext(Dispatchers.IO) {
try {
val request = Request.Builder().url(url).build()
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
return@withContext false
}
val inputStream = response.body?.byteStream() ?: return@withContext false
val contentLength = response.body?.contentLength() ?: 0
outputFile.outputStream().use { output ->
val buffer = ByteArray(8192)
var bytesRead: Int
var totalBytesRead = 0L
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
output.write(buffer, 0, bytesRead)
totalBytesRead += bytesRead
if (contentLength > 0) {
onProgress(totalBytesRead, contentLength)
}
}
}
return@withContext true
} catch (e: Exception) {
println("Download Error: ${e.message}")
return@withContext false
}
}
// Retry mechanism
suspend fun requestWithRetry(
url: String,
maxRetries: Int = 3,
delayMillis: Long = 1000
): String? = withContext(Dispatchers.IO) {
var lastException: Exception? = null
repeat(maxRetries) { attempt ->
try {
val request = Request.Builder().url(url).build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
}
} catch (e: Exception) {
lastException = e
println("Attempt $attempt failed: ${e.message}")
if (attempt < maxRetries - 1) {
delay(delayMillis)
}
}
}
println("All $maxRetries attempts failed")
return@withContext null
}
// Caching configuration
fun createCachedClient(cacheDir: File, cacheSize: Long = 10 * 1024 * 1024): OkHttpClient {
val cache = Cache(cacheDir, cacheSize)
return OkHttpClient.Builder()
.cache(cache)
.build()
}
// Request with timeout
suspend fun requestWithTimeout(
url: String,
timeoutSeconds: Int = 30
): String? = withContext(Dispatchers.IO) {
try {
val client = OkHttpClient.Builder()
.connectTimeout(timeoutSeconds.toLong(), java.util.concurrent.TimeUnit.SECONDS)
.readTimeout(timeoutSeconds.toLong(), java.util.concurrent.TimeUnit.SECONDS)
.build()
val request = Request.Builder().url(url).build()
val response = client.newCall(request).execute()
return@withContext response.body?.string()
} catch (e: Exception) {
println("Timeout Error: ${e.message}")
return@withContext null
}
}
}
// 4. REST API Client
class RestClient(private val baseUrl: String, private val context: Context) {
private val client = OkHttpClient()
suspend fun get(endpoint: String): String? = withContext(Dispatchers.IO) {
try {
val url = "$baseUrl$endpoint"
val request = Request.Builder()
.url(url)
.get()
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("GET $endpoint Error: ${e.message}")
return@withContext null
}
}
suspend fun post(endpoint: String, data: JSONObject): String? = withContext(Dispatchers.IO) {
try {
val url = "$baseUrl$endpoint"
val mediaType = "application/json".toMediaType()
val body = data.toString().toRequestBody(mediaType)
val request = Request.Builder()
.url(url)
.post(body)
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("POST $endpoint Error: ${e.message}")
return@withContext null
}
}
suspend fun put(endpoint: String, data: JSONObject): String? = withContext(Dispatchers.IO) {
try {
val url = "$baseUrl$endpoint"
val mediaType = "application/json".toMediaType()
val body = data.toString().toRequestBody(mediaType)
val request = Request.Builder()
.url(url)
.put(body)
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("PUT $endpoint Error: ${e.message}")
return@withContext null
}
}
suspend fun delete(endpoint: String): Boolean = withContext(Dispatchers.IO) {
try {
val url = "$baseUrl$endpoint"
val request = Request.Builder()
.url(url)
.delete()
.build()
val response = client.newCall(request).execute()
return@withContext response.isSuccessful
} catch (e: Exception) {
println("DELETE $endpoint Error: ${e.message}")
return@withContext false
}
}
}
// Main demonstration
suspend fun demonstrateHTTPRequests(context: Context) {
println("=== Android Kotlin HTTP Request Examples ===\n")
// 1. HttpURLConnection examples
println("--- 1. HttpURLConnection Examples ---")
val httpExample = HttpURLConnectionExample(context)
// Note: Replace with actual API endpoints for testing
// val getResult = httpExample.simpleGetRequest("https://api.example.com/data")
// println("GET Result: $getResult")
// 2. OkHttp examples
println("\n--- 2. OkHttp Examples ---")
val okHttpExample = OkHttpExample(context)
// val okHttpGet = okHttpExample.simpleGet("https://api.example.com/data")
// println("OkHttp GET: $okHttpGet")
// 3. Advanced operations
println("\n--- 3. Advanced HTTP Operations ---")
val advancedExample = AdvancedHttpExample(context)
// 4. REST client
println("\n--- 4. REST API Client ---")
val restClient = RestClient("https://api.example.com", context)
println("\n=== All HTTP Request Examples Completed ===")
}Téléchargement/Téléversement de Fichiers
Télécharger et téléverser des fichiers avec suivi de progression, fonctionnalité pause/reprise et gestion des tâches en arrière-plan
Difficulté
7/10
Temps estimé
35 min
Étiquettes
kotlin, android, networking, download, upload
Prérequis
Intermediate Kotlin, Storage permissions
// Android Kotlin File Download/Upload Examples
// Using DownloadManager, WorkManager, and OkHttp
import android.app.DownloadManager
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Environment
import android.webkit.MimeTypeMap
import androidx.work.*
import kotlinx.coroutines.*
import okhttp3.*
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
// 1. DownloadManager (System-managed downloads)
class SystemDownloadExample(private val context: Context) {
private val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
// Simple download using DownloadManager
fun downloadFile(url: String, title: String, description: String): Long {
val request = DownloadManager.Request(Uri.parse(url)).apply {
setTitle(title)
setDescription(description)
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
// Set destination
val fileName = URL(url).file.substringAfterLast("/")
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
fileName.substringAfterLast('.')
)
setMimeType(mimeType)
// Save to external storage
setDestinationInExternalFilesDir(
context,
Environment.DIRECTORY_DOWNLOADS,
fileName
)
}
return downloadManager.enqueue(request)
}
// Query download status
fun getDownloadStatus(downloadId: Long): Int {
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor: Cursor = downloadManager.query(query)
var status = -1
if (cursor.moveToFirst()) {
status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))
}
cursor.close()
return status
}
// Get download progress
fun getDownloadProgress(downloadId: Long): Int {
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor: Cursor = downloadManager.query(query)
var progress = 0
if (cursor.moveToFirst()) {
val bytesDownloaded = cursor.getInt(
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
)
val bytesTotal = cursor.getInt(
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
)
if (bytesTotal > 0) {
progress = (bytesDownloaded * 100 / bytesTotal)
}
}
cursor.close()
return progress
}
// Cancel download
fun cancelDownload(downloadId: Long) {
downloadManager.remove(downloadId)
}
}
// 2. Manual Download with Progress
class ManualDownloadExample(private val context: Context) {
// Download file with progress callback
suspend fun downloadFile(
url: String,
outputFile: File,
onProgress: (bytesRead: Long, contentLength: Long) -> Unit
): Boolean = withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
val urlObj = URL(url)
connection = urlObj.openConnection() as HttpURLConnection
connection.connectTimeout = 10000
connection.readTimeout = 10000
connection.requestMethod = "GET"
val responseCode = connection.responseCode
if (responseCode != HttpURLConnection.HTTP_OK) {
return@withContext false
}
val contentLength = connection.contentLengthLong
val inputStream = connection.inputStream
val outputStream = FileOutputStream(outputFile)
val buffer = ByteArray(8192)
var bytesRead: Int
var totalBytesRead = 0L
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
totalBytesRead += bytesRead
onProgress(totalBytesRead, contentLength)
}
outputStream.flush()
outputStream.close()
inputStream.close()
return@withContext true
} catch (e: Exception) {
println("Download Error: ${e.message}")
return@withContext false
} finally {
connection?.disconnect()
}
}
// Download with OkHttp
private val okHttpClient = OkHttpClient()
suspend fun downloadWithOkHttp(
url: String,
outputFile: File,
onProgress: (bytesRead: Long, contentLength: Long) -> Unit
): Boolean = withContext(Dispatchers.IO) {
try {
val request = Request.Builder().url(url).build()
val response = okHttpClient.newCall(request).execute()
if (!response.isSuccessful) {
return@withContext false
}
val inputStream = response.body?.byteStream() ?: return@withContext false
val contentLength = response.body?.contentLength() ?: 0
outputFile.outputStream().use { output ->
val buffer = ByteArray(8192)
var bytesRead: Int
var totalBytesRead = 0L
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
output.write(buffer, 0, bytesRead)
totalBytesRead += bytesRead
onProgress(totalBytesRead, contentLength)
}
}
return@withContext true
} catch (e: Exception) {
println("OkHttp Download Error: ${e.message}")
return@withContext false
}
}
// Resumeable download
data class DownloadState(
val url: String,
val outputFile: File,
val downloadedBytes: Long = 0
)
suspend fun resumeableDownload(
state: DownloadState,
onProgress: (bytesRead: Long, contentLength: Long) -> Unit
): Boolean = withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
val urlObj = URL(state.url)
connection = urlObj.openConnection() as HttpURLConnection
// Set range header for resume
if (state.downloadedBytes > 0 && state.outputFile.exists()) {
connection.setRequestProperty(
"Range",
"bytes=${state.downloadedBytes}-"
)
}
connection.connectTimeout = 10000
connection.readTimeout = 10000
val responseCode = connection.responseCode
if (responseCode !in listOf(HttpURLConnection.HTTP_OK, HttpURLConnection.HTTP_PARTIAL)) {
return@withContext false
}
val contentLength = if (responseCode == HttpURLConnection.HTTP_PARTIAL) {
connection.contentLength + state.downloadedBytes
} else {
state.downloadedBytes
}
val inputStream = connection.inputStream
val outputStream = if (state.downloadedBytes > 0) {
FileOutputStream(state.outputFile, true)
} else {
FileOutputStream(state.outputFile)
}
val buffer = ByteArray(8192)
var bytesRead: Int
var totalBytesRead = state.downloadedBytes
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
totalBytesRead += bytesRead
onProgress(totalBytesRead, contentLength)
}
outputStream.flush()
outputStream.close()
inputStream.close()
return@withContext true
} catch (e: Exception) {
println("Resumeable Download Error: ${e.message}")
return@withContext false
} finally {
connection?.disconnect()
}
}
}
// 3. File Upload
class FileUploadExample(private val context: Context) {
private val client = OkHttpClient()
// Upload single file
suspend fun uploadFile(
url: String,
file: File,
paramName: String = "file",
additionalParams: Map<String, String> = emptyMap()
): String? = withContext(Dispatchers.IO) {
try {
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
// Add additional parameters
additionalParams.forEach { (key, value) ->
requestBody.addFormDataPart(key, value)
}
// Add file
val mimeType = getMimeType(file)
requestBody.addFormDataPart(
paramName,
file.name,
file.asRequestBody(mimeType.toMediaTypeOrNull())
)
val request = Request.Builder()
.url(url)
.post(requestBody.build())
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("Upload Error: ${e.message}")
return@withContext null
}
}
// Upload multiple files
suspend fun uploadMultipleFiles(
url: String,
files: List<File>,
paramName: String = "files"
): String? = withContext(Dispatchers.IO) {
try {
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
files.forEach { file ->
val mimeType = getMimeType(file)
requestBody.addFormDataPart(
paramName,
file.name,
file.asRequestBody(mimeType.toMediaTypeOrNull())
)
}
val request = Request.Builder()
.url(url)
.post(requestBody.build())
.build()
val response = client.newCall(request).execute()
if (response.isSuccessful) {
return@withContext response.body?.string()
} else {
return@withContext null
}
} catch (e: Exception) {
println("Multiple Upload Error: ${e.message}")
return@withContext null
}
}
// Upload with progress
suspend fun uploadFileWithProgress(
url: String,
file: File,
paramName: String = "file",
onProgress: (bytesWritten: Long, contentLength: Long) -> Unit
): Boolean = withContext(Dispatchers.IO) {
try {
// Create counting request body
val countingRequestBody = object : RequestBody() {
override fun contentType(): okhttp3.MediaType? {
return getMimeType(file).toMediaTypeOrNull()
}
override fun writeTo(sink: BufferedSink) {
val source = file.source().buffer()
val contentLength = file.length()
var bytesWritten = 0L
val buffer = ByteArray(8192)
var bytesRead: Int
while (source.read(buffer).also { bytesRead = it } != -1) {
sink.write(buffer, 0, bytesRead)
bytesWritten += bytesRead
onProgress(bytesWritten, contentLength)
}
}
override fun contentLength(): Long = file.length()
}
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(paramName, file.name, countingRequestBody)
.build()
val request = Request.Builder()
.url(url)
.post(requestBody)
.build()
val response = client.newCall(request).execute()
return@withContext response.isSuccessful
} catch (e: Exception) {
println("Upload with Progress Error: ${e.message}")
return@withContext false
}
}
private fun getMimeType(file: File): String {
val extension = file.extension.lowercase()
return when (extension) {
"jpg", "jpeg" -> "image/jpeg"
"png" -> "image/png"
"gif" -> "image/gif"
"pdf" -> "application/pdf"
"txt" -> "text/plain"
"json" -> "application/json"
"mp4" -> "video/mp4"
"mp3" -> "audio/mpeg"
else -> "application/octet-stream"
}
}
}
// 4. Background Upload with WorkManager
class UploadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val fileUrl = inputData.getString("fileUrl") ?: return Result.failure()
val uploadUrl = inputData.getString("uploadUrl") ?: return Result.failure()
val file = File(fileUrl)
val uploader = FileUploadExample(applicationContext)
val result = uploader.uploadFile(uploadUrl, file)
return if (result != null) {
Result.success(workDataOf("response" to result))
} else {
Result.failure()
}
}
companion object {
fun enqueueUpload(context: Context, file: File, uploadUrl: String): UUID {
val data = workDataOf(
"fileUrl" to file.absolutePath,
"uploadUrl" to uploadUrl
)
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(constraints)
.setInputData(data)
.build()
WorkManager.getInstance(context).enqueue(uploadRequest)
return uploadRequest.id
}
}
}
// Main demonstration
suspend fun demonstrateFileDownloadUpload(context: Context) {
println("=== Android Kotlin File Download/Upload Examples ===\n")
// 1. System download
println("--- 1. System Download (DownloadManager) ---")
val systemDownload = SystemDownloadExample(context)
// Note: Replace with actual URL
// val downloadId = systemDownload.downloadFile(
// url = "https://example.com/file.pdf",
// title = "File Download",
// description = "Downloading file..."
// )
// 2. Manual download with progress
println("\n--- 2. Manual Download with Progress ---")
val manualDownload = ManualDownloadExample(context)
// val outputFile = File(context.getExternalFilesDir(null), "downloaded_file.pdf")
// manualDownload.downloadFile(
// url = "https://example.com/file.pdf",
// outputFile = outputFile,
// onProgress = { bytesRead, totalBytes ->
// val progress = (bytesRead * 100 / totalBytes).toInt()
// println("Download progress: $progress%")
// }
// )
// 3. File upload
println("\n--- 3. File Upload ---")
val uploadExample = FileUploadExample(context)
// val fileToUpload = File(context.filesDir, "upload.txt")
// uploadExample.uploadFile(
// url = "https://example.com/upload",
// file = fileToUpload,
// additionalParams = mapOf("userId" to "123")
// )
println("\n=== All File Download/Upload Examples Completed ===")
}Connexion WebSocket
Établir des connexions WebSocket, envoyer/recevoir des messages et gérer le cycle de vie de la connexion
Difficulté
7/10
Temps estimé
30 min
Étiquettes
kotlin, android, networking, websocket
Prérequis
Intermediate Kotlin, OkHttp library
// Android Kotlin WebSocket Examples
// Using OkHttp WebSocket and Java-WebSocket
import android.content.Context
import kotlinx.coroutines.*
import okhttp3.*
import okio.ByteString
import org.json.JSONObject
import java.util.concurrent.TimeUnit
// 1. Basic WebSocket with OkHttp
class BasicWebSocketExample(private val context: Context) {
private val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.build()
private var webSocket: WebSocket? = null
// Connect to WebSocket
fun connect(url: String) {
val request = Request.Builder()
.url(url)
.build()
val listener = object : WebSocketListener() {
override fun onOpen(ws: WebSocket, response: Response) {
println("WebSocket Connected")
println("Server response: ${response.message}")
// Send welcome message
ws.send("Hello from Android!")
}
override fun onMessage(ws: WebSocket, text: String) {
println("Received text: $text")
}
override fun onMessage(ws: WebSocket, bytes: ByteString) {
println("Received bytes: ${bytes.hex()}")
}
override fun onClosing(ws: WebSocket, code: Int, reason: String) {
println("Closing: $code $reason")
ws.close(code, reason)
}
override fun onClosed(ws: WebSocket, code: Int, reason: String) {
println("WebSocket Closed: $code $reason")
}
override fun onFailure(ws: WebSocket, t: Throwable, response: Response?) {
println("WebSocket Error: ${t.message}")
}
}
webSocket = client.newWebSocket(request, listener)
}
// Send text message
fun sendMessage(message: String) {
webSocket?.send(message)
}
// Send JSON message
fun sendJson(json: JSONObject) {
webSocket?.send(json.toString())
}
// Send binary data
fun sendBinary(data: ByteArray) {
webSocket?.send(ByteString.of(*data))
}
// Close connection
fun close() {
webSocket?.close(1000, "Goodbye!")
webSocket = null
}
}
// 2. Advanced WebSocket with Reconnection
class AdvancedWebSocketExample(
private val context: Context,
private val url: String
) {
private val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.build()
private var webSocket: WebSocket? = null
private var isConnected = false
private var reconnectAttempts = 0
private val maxReconnectAttempts = 5
private val reconnectDelay = 3000L // 3 seconds
private val messageQueue = mutableListOf<String>()
// Message callback interface
interface WebSocketCallback {
fun onConnected()
fun onMessage(text: String)
fun onMessage(bytes: ByteString)
fun onDisconnected()
fun onError(error: String)
}
private var callback: WebSocketCallback? = null
fun setCallback(cb: WebSocketCallback) {
this.callback = cb
}
// Connect with auto-reconnect
fun connect() {
val request = Request.Builder()
.url(url)
.addHeader("Origin", context.packageName)
.build()
val listener = object : WebSocketListener() {
override fun onOpen(ws: WebSocket, response: Response) {
println("WebSocket Connected")
isConnected = true
reconnectAttempts = 0
callback?.onConnected()
// Send queued messages
synchronized(messageQueue) {
messageQueue.forEach { message ->
ws.send(message)
}
messageQueue.clear()
}
}
override fun onMessage(ws: WebSocket, text: String) {
println("Received: $text")
callback?.onMessage(text)
}
override fun onMessage(ws: WebSocket, bytes: ByteString) {
println("Received bytes: ${bytes.hex()}")
callback?.onMessage(bytes)
}
override fun onClosing(ws: WebSocket, code: Int, reason: String) {
println("Closing: $code $reason")
}
override fun onClosed(ws: WebSocket, code: Int, reason: String) {
println("WebSocket Closed: $code $reason")
isConnected = false
callback?.onDisconnected()
// Attempt reconnection
attemptReconnect()
}
override fun onFailure(ws: WebSocket, t: Throwable, response: Response?) {
println("WebSocket Error: ${t.message}")
isConnected = false
callback?.onError(t.message ?: "Unknown error")
// Attempt reconnection
attemptReconnect()
}
}
webSocket = client.newWebSocket(request, listener)
}
// Attempt reconnection
private fun attemptReconnect() {
if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++
CoroutineScope(Dispatchers.IO).launch {
delay(reconnectDelay)
println("Reconnecting... Attempt $reconnectAttempts")
connect()
}
} else {
println("Max reconnection attempts reached")
}
}
// Send message with queueing
fun sendMessage(message: String) {
if (isConnected) {
webSocket?.send(message)
} else {
// Queue message for later
synchronized(messageQueue) {
messageQueue.add(message)
}
println("Message queued: $message")
}
}
// Close connection
fun close() {
reconnectAttempts = maxReconnectAttempts // Stop reconnection
webSocket?.close(1000, "User closing")
webSocket = null
isConnected = false
}
}
// 3. WebSocket Chat Example
class ChatWebSocket(private val context: Context) {
private val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.build()
private var webSocket: WebSocket? = null
data class ChatMessage(
val type: String, // "join", "message", "leave"
val username: String,
val content: String,
val timestamp: Long = System.currentTimeMillis()
)
interface ChatCallback {
fun onMessage(message: ChatMessage)
fun onUserJoined(username: String)
fun onUserLeft(username: String)
fun onConnectionStatus(connected: Boolean)
}
private var callback: ChatCallback? = null
fun setCallback(cb: ChatCallback) {
this.callback = cb
}
// Connect to chat server
fun connect(serverUrl: String, username: String) {
val request = Request.Builder()
.url(serverUrl)
.build()
val listener = object : WebSocketListener() {
override fun onOpen(ws: WebSocket, response: Response) {
println("Chat Connected as: $username")
callback?.onConnectionStatus(true)
// Send join message
val joinMessage = ChatMessage(
type = "join",
username = username,
content = ""
)
ws.send(toJson(joinMessage))
}
override fun onMessage(ws: WebSocket, text: String) {
val message = fromJson(text)
message?.let {
when (it.type) {
"join" -> callback?.onUserJoined(it.username)
"leave" -> callback?.onUserLeft(it.username)
"message" -> callback?.onMessage(it)
}
}
}
override fun onClosed(ws: WebSocket, code: Int, reason: String) {
println("Chat Closed")
callback?.onConnectionStatus(false)
}
override fun onFailure(ws: WebSocket, t: Throwable, response: Response?) {
println("Chat Error: ${t.message}")
callback?.onConnectionStatus(false)
}
}
webSocket = client.newWebSocket(request, listener)
}
// Send chat message
fun sendMessage(username: String, content: String) {
val message = ChatMessage(
type = "message",
username = username,
content = content
)
webSocket?.send(toJson(message))
}
// Leave chat
fun leave(username: String) {
val leaveMessage = ChatMessage(
type = "leave",
username = username,
content = ""
)
webSocket?.send(toJson(leaveMessage))
// Close connection
webSocket?.close(1000, "User leaving")
webSocket = null
}
private fun toJson(message: ChatMessage): String {
val json = JSONObject()
json.put("type", message.type)
json.put("username", message.username)
json.put("content", message.content)
json.put("timestamp", message.timestamp)
return json.toString()
}
private fun fromJson(json: String): ChatMessage? {
return try {
val obj = JSONObject(json)
ChatMessage(
type = obj.optString("type"),
username = obj.optString("username"),
content = obj.optString("content"),
timestamp = obj.optLong("timestamp", System.currentTimeMillis())
)
} catch (e: Exception) {
null
}
}
}
// 4. WebSocket Heartbeat/Ping
class HeartbeatWebSocket(
private val context: Context,
private val url: String
) {
private val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.pingInterval(30, TimeUnit.SECONDS) // Send ping every 30 seconds
.build()
private var webSocket: WebSocket? = null
private var heartbeatJob: Job? = null
// Connect with heartbeat
fun connect() {
val request = Request.Builder()
.url(url)
.build()
val listener = object : WebSocketListener() {
override fun onOpen(ws: WebSocket, response: Response) {
println("Heartbeat WebSocket Connected")
startHeartbeat(ws)
}
override fun onMessage(ws: WebSocket, text: String) {
println("Received: $text")
}
override fun onClosing(ws: WebSocket, code: Int, reason: String) {
stopHeartbeat()
}
override fun onClosed(ws: WebSocket, code: Int, reason: String) {
stopHeartbeat()
}
override fun onFailure(ws: WebSocket, t: Throwable, response: Response?) {
stopHeartbeat()
}
}
webSocket = client.newWebSocket(request, listener)
}
// Start heartbeat
private fun startHeartbeat(ws: WebSocket) {
heartbeatJob = CoroutineScope(Dispatchers.IO).launch {
while (isActive) {
delay(15000) // Send custom heartbeat every 15 seconds
val heartbeat = JSONObject().apply {
put("type", "heartbeat")
put("timestamp", System.currentTimeMillis())
}
ws.send(heartbeat.toString())
println("Heartbeat sent")
}
}
}
// Stop heartbeat
private fun stopHeartbeat() {
heartbeatJob?.cancel()
heartbeatJob = null
}
// Close connection
fun close() {
stopHeartbeat()
webSocket?.close(1000, "Closing")
webSocket = null
}
}
// 5. WebSocket Manager (Singleton)
class WebSocketManager private constructor(private val context: Context) {
companion object {
@Volatile
private var instance: WebSocketManager? = null
fun getInstance(context: Context): WebSocketManager {
return instance ?: synchronized(this) {
instance ?: WebSocketManager(context.applicationContext).also { instance = it }
}
}
}
private val connections = mutableMapOf<String, WebSocket>()
data class WebSocketConfig(
val url: String,
val key: String = url,
val autoReconnect: Boolean = true,
val reconnectDelay: Long = 3000L
)
// Connect with config
fun connect(config: WebSocketConfig, listener: WebSocketListener) {
val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.build()
val request = Request.Builder()
.url(config.url)
.build()
val ws = client.newWebSocket(request, listener)
connections[config.key] = ws
}
// Send message
fun send(key: String, message: String) {
connections[key]?.send(message)
}
// Close specific connection
fun close(key: String) {
connections[key]?.close(1000, "Closing")
connections.remove(key)
}
// Close all connections
fun closeAll() {
connections.values.forEach { it.close(1000, "Closing all") }
connections.clear()
}
}
// Main demonstration
fun demonstrateWebSocket(context: Context) {
println("=== Android Kotlin WebSocket Examples ===\n")
// 1. Basic WebSocket
println("--- 1. Basic WebSocket ---")
val basicWs = BasicWebSocketExample(context)
// basicWs.connect("wss://echo.websocket.org")
// basicWs.sendMessage("Hello WebSocket!")
// 2. Advanced WebSocket with reconnection
println("\n--- 2. Advanced WebSocket with Reconnection ---")
val advancedWs = AdvancedWebSocketExample(context, "wss://echo.websocket.org")
// advancedWs.setCallback(object : AdvancedWebSocketExample.WebSocketCallback {
// override fun onConnected() { println("Connected!") }
// override fun onMessage(text: String) { println("Message: $text") }
// override fun onMessage(bytes: ByteString) { println("Bytes received") }
// override fun onDisconnected() { println("Disconnected") }
// override fun onError(error: String) { println("Error: $error") }
// })
// advancedWs.connect()
// 3. Chat WebSocket
println("\n--- 3. Chat WebSocket ---")
val chatWs = ChatWebSocket(context)
// chatWs.connect("wss://chat.example.com", "User123")
// chatWs.sendMessage("User123", "Hello everyone!")
// 4. WebSocket Manager
println("\n--- 4. WebSocket Manager ---")
val wsManager = WebSocketManager.getInstance(context)
// wsManager.connect(
// WebSocketManager.WebSocketConfig("wss://echo.websocket.org"),
// listener
// )
println("\n=== All WebSocket Examples Completed ===")
}Outils
Outils souvent utilisés avec cet exemple
Associé