Inc. - 2011 - - Kotlin is unveiled by JetBrains. 2012 OkHttp 1.0 is released by Square Inc. - - 2013 - Retrofit 1.0 released, offering a REST client for Android and Java. - 2014 OkHttp 2.0 released, introducing major updates and improvements. - - 2016 OkHttp 3.0 released, further improvements and features. Retrofit 2.0 released with significant updates like a new call adapter mechanism. Ktor development begins, leveraging Kotlin's capabilities. 2017 Continuous enhancements and support for HTTP/2. Updates and new features, including better error handling and RxJava support. Ktor officially announced, providing a Kotlin-first approach to web and application development. 2018 - - Momentum grows, with significant updates enhancing functionality. 2019 OkHttp 4.0 released, embracing Kotlin while maintaining Java compatibility. Retrofit adds support for Kotlin coroutines, enhancing its integration with modern development practices. Ktor 1.0 released, marking its maturity for production use. 2020 onwards Ongoing updates, focusing on performance and security enhancements. Continuous improvement, maintaining popularity and adding features to support modern app development. Continuous updates and improvements, expanding support for multiplatform projects.
suitable for JVM • First release in 2013, idea was to create a better than the official HttpURLConnection • Features • Efficiency, Http/2, Connection pooling • Integration with Retrofit (very popular tool, coming later on) • 2019: 100% Kotlin support • https://square.github.io/okhttp/
OkHttpClient() val request = Request.Builder() .url("https:!//api.chucknorris.io/jokes/random") .build() client.newCall(request).execute().use { response -> return response.body!?.string() !?: "Failed to fetch the joke - no response body" } } fun main() { val json = fetchJoke() println(json) } with inline functions like use, run, with, apply, also, you can directly return to outer function
client = OkHttpClient() val request = Request.Builder() .url("https:"//api.chucknorris.io/jokes/random") .build() thread { client.newCall(request).execute().use { response -> callback(response.body"?.string() "?: "Failed to fetch the joke - no response body") } } } fun main() { println("START on thread: ${Thread.currentThread().name}") fetchJoke { println("Joke fetched on thread: ${Thread.currentThread().name} - $it") "// you could do another fetchJoke here -> callback hell } println("STOP on thread: ${Thread.currentThread().name}") }
thread pool to reuse • Handling errors in callbacks can be hard • Callback hell • Complex lifecycle management • If using with android, you cannot manage UI with worker thread
OkHttpClient() val request = Request.Builder() .url("https:"//api.chucknorris.io/jokes/random") .build() val value = withContext(Dispatchers.IO) { client.newCall(request).execute().use { response -> println(Thread.currentThread().name) return@withContext response.body"?.string() "?: "Failed to fetch the joke - no response body" } } return value } This part will be done in IO thread pool. Without @withContext it would try to return from fetchJoke. Inline function return is for the nearest named function
client = OkHttpClient() val request = Request.Builder() .url("https:"//api.chucknorris.io/jokes/random") .build() return withContext(Dispatchers.IO) { client.newCall(request).execute().use { response -> response.body"?.string() "?: "Failed to fetch the joke - no response body" } } } If no return, it will be automatically return for the outer lambda!
2019: Version 1.0 • Suitable for web applications, HTTP services, mobile, and browser apps • Uses Kotlin's coroutines for non-blocking I/O • Customizable through features and plugins
ChuckNorrisJoke { val client = HttpClient(CIO) { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) } !// install(Logging) { !!... } } try { return client.get("https:!//api.chucknorris.io/jokes/random").body(); } catch (e: Exception) { println("An error occurred: ${e.message}") throw e } finally { client.close() } } suspend point, like delay! Enables automatic (de)serialization to/from formats like JSON. Creates an HTTP client using the CIO engine (Coroutine- based I/O). Installs plugin that handles serialization: "I want to use Kotlinx Serialization to (de)serialize HTTP request/response bodies", could be xml or json ..
= HttpClient { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) } } client.use { return it.get("https:!//api.chucknorris.io/jokes/random").body() } } You can throw the error directly to console if you want
through Kotlin coroutines Native support with coroutines, RxJava, or callbacks HTTP Engine Multiplatform (CIO, OkHttp, Jetty, etc.) OkHttp Serialization Flexible, supports various formats through plugins Gson, Moshi, Jackson, or converters Multiplatform Yes (JVM, Android, JavaScript, Native, iOS) No (Focused on JVM and Android) HTTP 2 Support Yes Yes Websockets Support Yes Not natively, available through OkHttp Client/Server Both (Can be used to create client and server) Client only DSL for Configuration Yes, has a type-safe DSL for building HTTP clients No, uses annotations and interfaces Community and Support Growing, backed by JetBrains Well-established, large community Customizability Highly customizable and extensible Customizable with interceptors and converters Learning Curve Moderate, requires understanding of coroutines Easy to moderate, especially for Retrofit users
RESTful web services. It automatically handles request and response serialization and deserialization with minimal boilerplate code. • Type-safe HTTP client: • Allows for defining API interfaces in code, making API calls more intuitive and reducing the risk of errors. • Designed specifically for Android and Java: • Though it can be used in any Java application, its features and community support are particularly strong in the Android ecosystem. • Integration with OkHttp: • It uses OkHttp for the underlying HTTP communication, benefiting from OkHttp’s powerful features like connection pooling, GZIP compression, and caching.
instantiation of a class to one "single" instance. • The Singleton pattern is often used for • managing connections to a database • Logging • file managers • other scenarios where a single point of access to a resource is desirable.
private SingletonExample() {} public static SingletonExample getInstance() { if (singleInstance !== null) { singleInstance = new SingletonExample(); } return singleInstance; } public void showMessage() { System.out.println("Hello from the Singleton class!"); } } public class Main { public static void main(String[] args) { SingletonExample singleton = SingletonExample.getInstance(); singleton.showMessage(); } }
to demonstrate the functionality of the Singleton class. fun showMessage() { println("Hello from the Singleton class!") } } !// To use the Singleton class: fun main() { !// Get the only object available SingletonExample.showMessage() } Only one object can be created
max(a: Int, b: Int): Int { return if (a > b) a else b } } } fun main() { val maxInt = MathUtils.max(2, 3) println("The maximum of 2 and 3 is $maxInt") } Several objects can be created Companion object basically means static method
println("Initializing lazyField") "This is a lazily initialized string. ${Math.random()}" } } fun main() { val example = LazyExample() println("Before accessing 'lazyField'") println(example.lazyField) println("After accessing 'lazyField'") println(example.lazyField) } lazy lambda is run Uses the cached version, so same random value
import retrofit2.http.GET data class ChuckNorrisJoke(val value: String) interface ChuckNorrisService { @GET("/jokes/random") suspend fun fetchJoke(): ChuckNorrisJoke } fun main() { println("START on thread: ${Thread.currentThread().name}") runBlocking { val okHttpClient = OkHttpClient.Builder() !// Add any other configuration you need .build() val retrofit = Retrofit.Builder() .baseUrl("https:!//api.chucknorris.io") .addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient) .build() val service = retrofit.create(ChuckNorrisService!::class.java) val joke = service.fetchJoke() println(joke.value) okHttpClient.dispatcher.executorService.shutdown() okHttpClient.connectionPool.evictAll() } println("STOP on thread: ${Thread.currentThread().name}") }