Why doesn’t the program exit immediately after retrieving the data via HTTP?
The application doesn't exit because some non-daemon threads are still running.
Retrofit uses OkHttpClient, which creates threads that stay alive even after requests finish.
These threads are typically kept alive for connection reuse.
You can see these threads by adding this code at the end of the main function:
Thread.getAllStackTraces()
.keys
.filter { !it.isDaemon }
.forEach { println(it.name) }
How can I make the program exit when the data is retrieved?
I would suggest 2 options:
1) Use an OkHttpClient that doesn’t keep non-daemon threads running
You need to build such OkHttpClient and pass it when building Retrofit.
In your original code, you don’t call client(httpClient), so Retrofit uses the default OkHttpClient.
object RetrofitClient {
private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
val httpClient by lazy {
val dispatcher = Dispatcher(
Executors.newCachedThreadPool {
Thread(it).apply { isDaemon = true }
}
)
OkHttpClient.Builder()
.dispatcher(dispatcher)
.connectionPool(ConnectionPool(0, 1, TimeUnit.MILLISECONDS))
.build()
}
val instance: ApiService by lazy {
Retrofit.Builder()
.client(httpClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}
fun main() = runBlocking {
val posts = RetrofitClient.instance.getPosts()
posts.forEach { println(it) }
}
2) Explicitly shut down OkHttpClient's internal resources
Write a closeHttpClient() function that closes OkHttpClient,
and call it at the end of the main function.
The implementation of closeHttpClient() follows the guidance from "Shutdown isn't necessary" of OkHttpClient documentation.
object RetrofitClient {
private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
private val httpClient by lazy { OkHttpClient.Builder().build() }
val instance: ApiService by lazy {
Retrofit.Builder()
.client(httpClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
fun closeHttpClient() {
httpClient.dispatcher().executorService().shutdown()
httpClient.connectionPool().evictAll()
httpClient.cache()?.close()
}
}
fun main() = runBlocking {
val posts = RetrofitClient.instance.getPosts()
posts.forEach { println(it) }
RetrofitClient.closeHttpClient()
}