일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 스택 큐 차이
- 스택 자바 코드
- 안드로이드 라이선스 종류
- 안드로이드 레트로핏 사용법
- rxjava hot observable
- 안드로이드 유닛테스트란
- 큐 자바 코드
- jvm 작동 원리
- 서비스 쓰레드 차이
- jvm이란
- 안드로이드 os 구조
- ANR이란
- android ar 개발
- rxjava cold observable
- 안드로이드 유닛 테스트
- 자바 다형성
- rxjava disposable
- 플러터 설치 2022
- 2022 플러터 안드로이드 스튜디오
- ar vr 차이
- 클래스
- 안드로이드 레트로핏 crud
- 2022 플러터 설치
- 멤버변수
- 서비스 vs 쓰레드
- Rxjava Observable
- 안드로이드 유닛 테스트 예시
- 객체
- android retrofit login
- 안드로이드 라이선스
- Today
- Total
나만을 위한 블로그
[Android] Ktor란? 본문
최근 미디엄에서 안드로이드 관련 게시물을 보다가 간간이 Ktor라는 걸 레트로핏과 비교하는 글을 여럿 봤다.
레트로핏과 비교하는 거라면 비동기 통신 라이브러리란 건데 이게 뭔지 알아보고자 포스팅한다.
Ktor 공식 홈페이지에서 설명하는 Ktor는 아래와 같다.
https://ktor.io/docs/welcome.html
Ktor는 웹 앱, HTTP 서비스, 모바일 및 브라우저 앱과 같은 연결된 앱을 쉽게 구축할 수 있는 프레임워크다. 최신 연결 앱은 사용자에게 최고의 경험을 제공하기 위해 비동기 방식이어야 하며 코틀린 코루틴은 쉽고 간단하게 이를 수행할 수 있는 기능을 제공한다. Ktor의 목표는 연결된 앱을 위한 종단 간(end-to-end) 멀티플랫폼 프레임워크를 제공하는 것이다
공식 홈페이지에선 Ktor를 프레임워크라고 설명하고 모바일에서도 사용 가능해 보인다.
다른 Ktor의 정의를 좀 더 찾아봤다.
https://www.codingame.com/playgrounds/36835/ktor-as-a-backend-application
Ktor는 개발자가 코틀린으로 비동기 클라이언트 및 서버 앱을 작성할 수 있게 하는 코틀린 프레임워크다. 완전히 호환되지는 않지만 JVM, 자바스크립트, 안드로이드, iOS 같은 여러 플랫폼을 대상으로 한다
https://medium.com/google-developer-experts/how-to-use-ktor-client-on-android-dcdeddc066b9
Ktor는 마이크로서비스 및 웹 앱을 만들기 위한 비동기식 오픈소스 프레임워크다. Jetbrains에서 코틀린으로 만들었다. 설치, 사용이 간편하며 실행 파이프라인에 단계를 추가하려는 경우 확장 가능하다. 코루틴의 비동기 속성으로 인해 여러 요청을 수신할 수 있고 멀티플랫폼이기도 하다. 즉 서버뿐 아니라 Ktor 클라이언트를 써서 안드로이드, iOS, JS에서 마이크로서비스를 사용할 수도 있다
Ktor 클라이언트를 쓰면 요청 생성, 응답 처리 및 인증, JSON 직렬화 등과 같은 기능으로 기능을 확장할 수 있다
https://medium.com/geekculture/what-is-ktor-and-why-should-you-learn-it-b7e5600a4d50
다음은 Ktor의 가장 중요한 기능 일부다
- 라우팅
- 요청, 응답 처리
- 템플릿(Templating)
- 컨텐츠 협상(negotiation) 및 직렬화
- 인증 및 권한 부여
- ions
- HTTP
- 소켓
- 모니터링
- 관리
이외에 Ktor에 대해 검색해보면 아직 앱 클라이언트 관련 이야기보다는 백엔드와 연관지어 설명하는 글들이 좀 더 많다. 예제 코드 또한 백엔드 위주로 작성해서 포스팅한 사람들이 많이 있다.
국내 백엔드 생태계는 자바 스프링이 꽉 잡고 있다고 알고 있는데 조금씩 코틀린 스프링(코프링)을 도입하는 곳도 있다는데 Ktor가 어떻게 될지는 좀 더 두고봐야겠다. 안드로이드 진영에서도 Ktor vs Retrofit 같은 vs 놀이가 유행이지만 앞으로 어떻게 될지 모르니 안드로이드 개발자로서도 관심있게 지켜보면 좋을 것 같다.
그리고 지켜볼 뿐만 아니라 어떻게 작동하는지도 코드로 짜보는 게 좋을 것 같아서 간단하게 예제를 찾아봤다.
먼저 앱 수준 gradle에 의존성을 추가한다.
// Ktor
implementation "io.ktor:ktor-client-core:1.6.3"
implementation "io.ktor:ktor-client-android:1.6.3"
implementation "io.ktor:ktor-client-serialization:1.6.3"
implementation "io.ktor:ktor-client-logging:1.6.3"
implementation "io.ktor:ktor-client-gson:1.6.3"
모든 의존성이 Ktor를 안드로이드에서 쓰기 위해 필요한 것은 아니니 필요한 것만 골라 쓰자. 여기선 이 의존성들을 모두 넣은 채로 진행한다.
그리고 요청을 보내고 응답을 받을 때 사용할 data class를 각각 정의한다.
import kotlinx.serialization.Serializable
@Serializable
data class PostRequest(
val body: String,
val title: String,
val userId: Int
)
import kotlinx.serialization.Serializable
@Serializable
data class PostResponse(
val body: String,
val title: String,
val id: Int,
val userId: Int
)
요청, 응답 모두 @Serializable을 쓰는 것이 눈에 띈다. 다음으로 요청을 보낼 주소를 정의한다.
object HttpRoutes {
const val POSTS = "https://jsonplaceholder.typicode.com/posts"
}
그리고 인터페이스를 정의한다. 레트로핏과는 많이 다른 형태라 신선하다.
import io.ktor.client.*
import io.ktor.client.engine.android.*
import io.ktor.client.features.json.*
import io.ktor.client.features.json.serializer.*
import io.ktor.client.features.logging.*
interface PostsService {
companion object {
fun create(): PostsService {
return PostsServiceImpl(
client = HttpClient(Android) {
install(Logging) {
level = LogLevel.ALL
}
install(JsonFeature) {
serializer = KotlinxSerializer()
}
}
)
}
}
suspend fun getPosts(): List<PostResponse>
suspend fun createPost(postRequest: PostRequest): PostResponse?
}
companion object로 create()를 만드는 부분이 기존 레트로핏과는 많이 다르다. 대신 좀 더 직관적으로 보이는 건 있다.
어떤 레벨의 로그까지 표시할 것인지와 JSON 직렬화를 저렇게 정의하니 직관적으로 보이는 느낌이다. 그 외에는 코루틴을 쓴다면 익숙한 키워드인 suspend를 붙인 함수 2개 뿐이다.
그리고 이 인터페이스를 구현하는 클래스를 하나 만든다.
import android.util.Log
import io.ktor.client.*
import io.ktor.client.features.*
import io.ktor.client.request.*
import io.ktor.http.*
class PostsServiceImpl(
private val client: HttpClient
) : PostsService {
private val TAG = this.javaClass.simpleName
override suspend fun getPosts(): List<PostResponse> {
return try {
client.get {
url(HttpRoutes.POSTS)
}
} catch (e: RedirectResponseException) {
// 3xx responses
Log.e(TAG, "Error : ${e.response.status.description}")
emptyList()
} catch (e: ClientRequestException) {
// 4xx responses
Log.e(TAG, "Error : ${e.response.status.description}")
emptyList()
} catch(e: ServerResponseException) {
// 5xx responses
Log.e(TAG, "Error : ${e.response.status.description}")
emptyList()
} catch(e: Exception) {
Log.e(TAG, "Error : ${e.message}")
emptyList()
}
}
override suspend fun createPost(postRequest: PostRequest): PostResponse? {
return try {
client.post<PostResponse> {
url(HttpRoutes.POSTS)
contentType(ContentType.Application.Json)
body = postRequest
}
} catch (e: RedirectResponseException) {
// 3xx responses
Log.e(TAG, "Error : ${e.response.status.description}")
null
} catch (e: ClientRequestException) {
// 4xx responses
Log.e(TAG, "Error : ${e.response.status.description}")
null
} catch(e: ServerResponseException) {
// 5xx responses
Log.e(TAG, "Error : ${e.response.status.description}")
null
} catch(e: Exception) {
Log.e(TAG, "Error : ${e.message}")
null
}
}
}
이제 지금까지 만든 것들을 액티비티에서 사용하자.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.example.ktorpractice.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlin.coroutines.CoroutineContext
class ThirdActivity : AppCompatActivity(), CoroutineScope {
private val TAG = this.javaClass.simpleName
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
private val client = PostsService.create()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
setContentView(R.layout.activity_third)
CoroutineScope(Dispatchers.IO).launch {
val response: List<PostResponse> = client.getPosts()
for (i in response.indices) {
Log.e(TAG, "response[i].id : ${response[i].id}")
Log.e(TAG, "response[i].body : ${response[i].body}")
Log.e(TAG, "response[i].title : ${response[i].title}")
Log.e(TAG, "response[i].userId : ${response[i].userId}")
}
}
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
이렇게 하고 실행하면 로그캣에 아래와 같은 로그들이 출력된다.
body 밑에는 개행문자 때문에 밑으로 내려간 문장들이 있는데 잘려서 안 보인다. 정리가 안 된 코드지만 레트로핏보다 좀 더 직관적인 코드를 써서 서버와 통신하는 걸 볼 수 있다.
간단하게 Ktor를 안드로이드에서 쓰는 법을 확인해봤다.
이것이 레트로핏을 대체할 수 있을지는 모르겠지만 알아둬서 나쁜 개발 지식은 없기 때문에 틈날 때마다 Hilt를 써서 MVVM 클린 아키텍처에 Ktor를 적용한 미니 프로젝트를 만들어 보면 재밌을 것 같다.
'Android' 카테고리의 다른 글
[Android] CollapsingToolbarLayout이란? CollapsingToolbarLayout 예제 (0) | 2022.06.19 |
---|---|
[Android] Navigation Component란? Navigation 사용법 (0) | 2022.06.19 |
[Android] EncryptedSharedPreference란? (0) | 2022.06.12 |
[Android] 코틀린으로 구글 로그인 구현하기 (0) | 2022.06.09 |
[Android] 안드로이드 스튜디오 범블비에서 SHA-1 키 빨리 확인하는 법 (0) | 2022.06.09 |