본문 바로가기

Android/Library

[Library] Retrofit이 뭔데?

Retrofit?

- Retrofit?

Retrofit란 Square사의 HTTP 클라이언트 라이브러리인 OkHttp를 기반으로 하는 안드로이드 앱 및 Java 기반의 웹 서비스에서 네트워크 통신을 처리하기 위한 라이브러리이다. Retrofit은 RESTful 웹 서비스와의 통신을 간편하게 만들어준다.

 

Retrofit을 통해 API를 호출하고 서버와 통신하려면 일반적으로 Retrofit을 통해 주고받는 데이터를 직렬화/역직렬화하고 이를 다시 원하는 객체로 변환하기 위한 Converter가 필요하다. 이를 위해 Retrofit은 Gson, Moshi 등 직렬화 라이브러리들과 함께 사용한다. 이 글에서는 대표적인 직렬화 라이브러리 중 Moshi와 함께 간단한 로그인 기능을 구현해보고자 한다.

 

먼저 Retrofit을 사용하려면 프로젝트 내의 사용하고자 하는 모둘의 gradle의 dependencies에 라이브러리를 추가해주어야 한다.

// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Moshi
implementation("com.squareup.retrofit2:converter-moshi:1.15.0")

 

서버와 인터넷을 이용해 네트워크 통신을 할 것 이기때문에 AndroidManifest.xml에 인터넷 권한을 열어준다

<uses-permission android:name="android.permission.INTERNET" />

 

 

위의 과정을 거치면 1차적인 프로젝트 내의 세팅은 끝이 났다. 개발자에 따라 Hilt 등 다른 라이브러리를 함께 사용할 수 있겠지만 이 글에서는 Hilt 없이 간단한 예제코드와 함께 Retrofit의 사용 방법을 설명할 것이다.



먼저 Moshi를 사용해 JSON 데이터를 파싱하기 위한 데이터 클래스를 정의한다.

// 서버로 전송되는 로그인 요청
data class LoginRequest(
    @Json(name = "username") val username: String,
    @Json(name = "password") val password: String
)

// 서버로부터 수신되는 로그인 응답
data class LoginResponse(
    @Json(name = "token") val token: String,
    @Json(name = "message") val message: String
)

 

Retrofit을 사용해 서버의 API를 호출할 API 인터페이스를 작성한다.

interface AuthService {
    @POST("/login")
    suspend fun login(
        @Body request: LoginRequest
    ): Response<LoginResponse>
}

 

Retrofit 인스턴스를 생성하는 함수를 작성한다. 되도록이면 메모리 낭비를 막기 위해 싱글톤 패턴으로 구현하는 방식이 보편적이다.

object RetrofitInstance {
    private const val BASE_URL = "https://api.jongjong.com/"

    val authService: AuthService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(MoshiConverterFactory.create())
            .build()
            .create(AuthService::class.java)
    }
}

 

 

이제 UI를 구현해 사용자가 UI를 통해 통신하는데 필요한 인자들을 넘겨야할 것이다. 아래는 간단한 UI 코드이다. 더 빠르고 Retrofit의 동작에 집중하기 위해 ViewModel과 같은 디자인패턴은 생략했으니 이를 감안하고 보길 바란다.

@Composable
fun LoginScreen() {
    // UI 상태를 관리하는 변수들
    var username by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }
    var loginResult by remember { mutableStateOf("") }
    var isLoading by remember { mutableStateOf(false) }

    // suspend 함수 호출을 위해 코루틴 스코프 생성
    val scope = rememberCoroutineScope()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // 사용자 이름 입력 필드
        TextField(
            value = username,
            onValueChange = { username = it },
            label = { Text("Username") },
            modifier = Modifier.fillMaxWidth()
        )

        // 비밀번호 입력 필드
        TextField(
            value = password,
            onValueChange = { password = it },
            label = { Text("Password") },
            visualTransformation = PasswordVisualTransformation(),
            modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
        )

        // 로그인 버튼
        Button(
            onClick = {
                // 로그인 버튼을 클릭하면 코루틴을 사용하여 API 호출
                scope.launch {
                    isLoading = true
                    try {
                        val response: Response<LoginResponse> = RetrofitInstance.authService.login(
                            LoginRequest(username, password)
                        )
                        if (response.isSuccessful) {
                            loginResult = "Login successful! Token: ${response.body()?.token}"
                        } else {
                            loginResult = "Login failed: ${response.errorBody()?.string()}"
                        }
                    } catch (e: HttpException) {
                        loginResult = "Login failed: ${e.message}"
                    } catch (e: Exception) {
                        loginResult = "An error occurred: ${e.message}"
                    } finally {
                        isLoading = false
                    }
                }
            },
            modifier = Modifier.fillMaxWidth().padding(top = 16.dp),
            enabled = !isLoading
        ) {
            Text(if (isLoading) "Logging in..." else "Login")
        }

        // 로그인 결과 표시
        if (loginResult.isNotEmpty()) {
            Text(
                text = loginResult,
                modifier = Modifier.padding(top = 16.dp)
            )
        }
    }
}

 

안드로이드의 서버통신 라이브러리인 Retrofit 사용 방법을 간단한 예시 코드와 함께 알아보았다. 안드로이드에서 사용할 수 있는 서버통신 라이브러리는 Retrofit 외에 Volley, OkHttp 등 여러 통신 라이브러리가 있으니 개발 상황을 고려해 사용하면 된다.