본문 바로가기

android studio

[Android] Retrofit2 사용법 (Jetpack Compose)

1. Retrofit2 의존성 추가

dependencies {
    implementation("com.squareup.retrofit2:retrofit:2.9.0") // Retrofit 기본 라이브러리
    implementation("com.squareup.retrofit2:converter-gson:2.9.0") // JSON 변환을 위한 Gson 컨버터
    implementation("com.google.code.gson:gson:2.10") // Gson 라이브러리
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") // 코루틴 지원
}

 

 

2. Retrofit 인터페이스(API 서비스) 생성

 

API 응답 데이터 모델

import com.google.gson.annotations.SerializedName

data class Post(
    @SerializedName("userId") val userId: Int,
    @SerializedName("id") val id: Int,
    @SerializedName("title") val title: String,
    @SerializedName("body") val body: String
)

 

 

Retrofit API 인터페이스

import retrofit2.http.GET
import retrofit2.http.Path
import kotlinx.coroutines.flow.Flow

interface ApiService {
    @GET("posts")
    suspend fun getPosts(): List<Post>

    @GET("posts/{id}")
    suspend fun getPostById(@Path("id") id: Int): Post
}

 

  • @GET("posts") → 모든 게시글을 가져오는 API
  • @GET("posts/{id}") → 특정 게시글을 ID로 가져오는 API
  • suspend 키워드를 사용하여 코루틴에서 동작할 수 있도록 함.

 

 

3. Retrofit 인스턴스 생성 (Singleton)

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitInstance {
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"

    val api: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create()) // JSON 변환
            .build()
            .create(ApiService::class.java)
    }
}

 

 

 

 

4. ViewModel에서 API 호출하기

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class PostViewModel : ViewModel() {
    private val _posts = MutableStateFlow<List<Post>>(emptyList())
    val posts: StateFlow<List<Post>> = _posts

    init {
        fetchPosts()
    }

    private fun fetchPosts() {
        viewModelScope.launch {
            try {
                val response = RetrofitInstance.api.getPosts()
                _posts.value = response
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}
  • viewModelScope.launch를 사용하여 코루틴에서 네트워크 요청을 비동기적으로 실행함.
  • StateFlow를 사용하여 Compose UI에서 collectAsState()로 상태를 감지할 수 있도록 설정.

 

 

5. Compose에서 데이터 표시하기

import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.*
import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun PostScreen(postViewModel: PostViewModel = viewModel()) {
    val posts by postViewModel.posts.collectAsState()

    Scaffold(
        topBar = { TopAppBar(title = { Text("Posts") }) }
    ) { paddingValues ->
        if (posts.isEmpty()) {
            Box(
                modifier = Modifier.fillMaxSize(),
                contentAlignment = Alignment.Center
            ) {
                CircularProgressIndicator()
            }
        } else {
            LazyColumn(modifier = Modifier.padding(paddingValues)) {
                items(posts) { post ->
                    Card(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(8.dp),
                        elevation = 4.dp
                    ) {
                        Column(modifier = Modifier.padding(16.dp)) {
                            Text(text = post.title, style = MaterialTheme.typography.h6)
                            Spacer(modifier = Modifier.height(8.dp))
                            Text(text = post.body, style = MaterialTheme.typography.body1)
                        }
                    }
                }
            }
        }
    }
}

 

  • viewModel<PostViewModel>() → ViewModel을 가져옴
  • collectAsState() → Flow를 Compose에서 구독하여 UI가 자동 업데이트됨
  • LazyColumn → 리스트를 효율적으로 표시
  • CircularProgressIndicator() → 데이터가 없을 때 로딩 표시

 

 

 

6. Retrofit과 Hilt DI 사용하기 (선택)

Hilt 모듈 추가

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"

    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

 

 

ViewModel에서 Hilt로 API 사용

import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class PostViewModel @Inject constructor(
    private val apiService: ApiService
) : ViewModel() {
    private val _posts = MutableStateFlow<List<Post>>(emptyList())
    val posts: StateFlow<List<Post>> = _posts

    init {
        fetchPosts()
    }

    private fun fetchPosts() {
        viewModelScope.launch {
            try {
                _posts.value = apiService.getPosts()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
}