Jetpack ComopseでHTTP通信処理のいい感じのコードが転がってなかったので作ってみました
Kotlin独自のAPIなどは無いようなので今回はJavaのHttpURLConnectionを使います
OkHttp3などもありますが保守性のためなるべくサードベンダー製は使用しない方向です
developerではRetrofitを使用した例が紹介されています
https://developer.android.com/courses/pathways/android-basics-compose-unit-5-pathway-1?hl=ja#codelab-https://developer.android.com/codelabs/basic-android-kotlin-compose-getting-data-internet
他で使う場合再度説明がめんどいのでAndroid LibraryにしてGitHubにあげておきました
https://github.com/smurata-bpse/HttpClient
とりあえずgetだけ
実務で使う場合は通信キャンセルやマルチパート対応やベーシック認証の処理など追加すると思います
/**
* ```AndroidManifest.xml
* <manifest>
* <uses-permission android:name="android.permission.INTERNET" />
* ```
*/
class HttpClient {
private suspend fun sendRequest(
url: String,
timeout: Int = 5 * 1000,
onError: (e: Exception) -> Unit,
onCompleted: (responseCode: Int, responseData: ByteArray) -> Unit
) = coroutineScope {
withContext(Dispatchers.IO) {
try {
val connection = URL(url).openConnection() as HttpURLConnection
connection?.apply {
requestMethod = "GET"
connectTimeout = timeout
readTimeout = timeout
// connect()はgetResponseCode()を使用する場合は省略可 ※ここではresponseCode
connect()
yield()
val stream = if (responseCode == HttpURLConnection.HTTP_OK) inputStream else errorStream
val responseData = ByteArrayOutputStream()
try {
val buf = ByteArray(1024)
var size: Int
while (stream.read(buf).also { size = it } != -1) {
responseData.write(buf, 0, size)
}
responseData.flush()
}
catch (e: Exception) {
throw e
}
finally {
// JDK7からAutoCloseableになったためclose()不要
onCompleted(responseCode, responseData.toByteArray())
connection.disconnect()
}
}
}
catch (e: Exception) {
onError(e)
}
}
}
companion object {
const val OK = HttpURLConnection.HTTP_OK
suspend fun Get(
url: String,
timeout: Int = 5 * 1000,
onError: (e: Exception) -> Unit = {},
onCompleted: (responseCode: Int, responseData: ByteArray) -> Unit
) {
HttpClient().sendRequest(url, timeout = timeout, onError = onError, onCompleted = onCompleted)
}
}
}
使い方はこんな感じです
val scope = rememberCoroutineScope()
var job: Job? by remember { mutableStateOf(null) }
val url = "http://abehiroshi.la.coocan.jp/"
Column(Modifier.fillMaxSize()) {
Button(onClick = {
if (job == null || job!!.isCompleted || job!!.isCancelled) {
job = scope.launch {
HttpClient.Get(url) { code, data ->
if (code == HttpClient.OK) {
text = String(data, Charsets.UTF_8)
}
}
}
}
}
}) {
Text("get")
}
}
軽量で有名な阿部さんのサイトに接続してみます
阿部さんのサイトはHTTPSに対応してないので例外を許可する以下を追加します
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">abehiroshi.la.coocan.jp</domain>
</domain-config>
</network-security-config>
<manifest>
<application
android:networkSecurityConfig="@xml/network_security_config"
>
Android Studio Giraffe 2022.3.1 built on June 29, 2023