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()
}
}
}
}
'android studio' 카테고리의 다른 글
[Android] Recomposition / State Management (Jetpack Compose) (0) | 2025.03.06 |
---|---|
[Android] Animation 사용법 (Jetpack Compose) (0) | 2025.03.04 |
[Android] MaterialTheme 사용법 (Jetpack Compose) (0) | 2025.03.03 |
[Android] Navigation 사용법 (Jetpack Compose) (0) | 2025.02.28 |
[Android] Slider 사용법 (Jetpack Compose) (0) | 2025.02.27 |