2021.05.14 - [안드로이드/AAC, MVVM] - [Android] Retrofit 사용하여 서버와 http 통신하기 - (1) 기본적인 사용법
와 이어지는 글입니다.
저번에는
이와 같이 posts/1 의 값을 불러오는 메소드를 사용하였다.
https://jsonplaceholder.typicode.com/posts
여기서 보면 posts/ 가 1~100까지 있는것을 알 수 있다.
여기서 임의의 값을 입력받아서 그 값을 불러오려고 한다.
// 가능한 HTTP 동작들을 정의해놓은 인터페이스
interface SimpleApi {
@GET("posts/1")
suspend fun getPost() : Response<Post>
@GET("posts/{postNumber}")
suspend fun getPost2(
@Path("postNumber") number : Int
) : Response<Post>
}
인터페이스에서 숫자를 입력받아 그 값에 해당하는 결과를 출력하는 함수 getPost2를 작성해준다.
@Path 어노테이션을 사용하여 위의 @GET 과 연결해준다.
// 뷰모델에 사용하기 위한 데이터를 통신함
class Repository {
suspend fun getPost() : Response<Post> {
return RetrofitInstance.api.getPost()
}
suspend fun getPost2(number : Int) : Response<Post> {
return RetrofitInstance.api.getPost2(number)
}
}
실질적으로는 여기서 메소드를 사용한다.
// 데이터를 처리함
class MainViewModel(private val repository : Repository) : ViewModel() {
val myResponse : MutableLiveData<Response<Post>> = MutableLiveData()
val myResponse2 : MutableLiveData<Response<Post>> = MutableLiveData()
fun getPost() {
viewModelScope.launch {
val response = repository.getPost()
myResponse.value = response
}
}
fun getPost2(number : Int){
viewModelScope.launch {
val response = repository.getPost2(number)
myResponse2.value = response
}
}
}
결과값을 받을 myResponse2 라이브 데이터를 생성해주고, 아까 저장소에서 정의한 메소드를 사용하여 할당한다.
입력 받고 그 값을 표시할 수 있게 레이아웃을 바꿔준다.
class MainActivity : AppCompatActivity() {
private lateinit var viewModel : MainViewModel
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 뷰바인딩
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val repository = Repository()
val viewModelFactory = MainViewModelFactory(repository)
viewModel = ViewModelProvider(this,viewModelFactory).get(MainViewModel::class.java)
viewModel.myResponse2.observe(this, Observer {
if(it.isSuccessful){
binding.textView.text = it.body().toString()
}
else{
binding.textView.text = it.code().toString()
}
})
binding.button.setOnClickListener {
val myNumber = binding.editTextView.text.toString()
viewModel.getPost2(Integer.parseInt(myNumber))
}
}
}
숫자 입력 후 버튼 클릭시 통신한 값이 출력되도록 한다. 통신 실패시 에러코드를 출력하도록 한다.
잘 출력되는 것을 확인할 수 있다.
없는 주소를 사용할 시 에러코드를 출력한다.
쿼리로 특정 조건에 맞는 데이터를 불러 올 수도 있다.
@GET("posts")
suspend fun getCustomPost(
@Query("userId") userId : Int
): Response<List<Post>>
suspend fun getCustomPosts(userId : Int) : Response<List<Post>> {
return RetrofitInstance.api.getCustomPost(userId)
}
val myCustomPosts : MutableLiveData<Response<List<Post>>> = MutableLiveData()
fun getCustomPosts(userId : Int){
viewModelScope.launch {
val response = repository.getCustomPosts(userId)
myCustomPosts.value = response
}
}
아까와 같이 각각 인터페이스,저장소,뷰모델에 추가해준다.
쿼리로 입력받은 userId에 맞는 결과값을 리스트로 반환할 것이다.
@Query 어노테이션으로 쿼리를 작성할 수 있다.
class MainActivity : AppCompatActivity() {
private lateinit var viewModel : MainViewModel
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 뷰바인딩
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val repository = Repository()
val viewModelFactory = MainViewModelFactory(repository)
viewModel = ViewModelProvider(this,viewModelFactory).get(MainViewModel::class.java)
viewModel.myCustomPosts.observe(this, Observer {
if(it.isSuccessful){
binding.textView.text = it.body().toString()
it.body()?.forEach{ post ->
Log.d("Response",post.myUserId.toString())
Log.d("Response",post.id.toString())
Log.d("Response",post.title)
Log.d("Response",post.body)
Log.d("Response","-------------------------")
}
}
else{
binding.textView.text = it.code().toString()
}
})
binding.button.setOnClickListener {
val myNumber = binding.editTextView.text.toString()
viewModel.getCustomPosts(Integer.parseInt(myNumber))
}
}
}
리스트 형태로 반환되므로 확인시 보기 편하게 foreach로 로그에 찍는다.
아이디에 맞는 모든 값이 출력된 것을 확인할 수 있다.
https://jsonplaceholder.typicode.com/posts?userId=3
주소창에서 ?과 조건을 작성하면 동일한 결과값을 확인할 수 있다.
또한 조건을 여러개 사용할 수도 있다.
@GET("posts")
suspend fun getCustomPost2(
@Query("userId") userId : Int,
@Query("_sort") sort : String,
@Query("_order") order : String
): Response<List<Post>>
suspend fun getCustomPosts2(userId : Int, sort : String, order : String) : Response<List<Post>> {
return RetrofitInstance.api.getCustomPost2(userId,sort,order)
}
val myCustomPosts2 : MutableLiveData<Response<List<Post>>> = MutableLiveData()
fun getCustomPosts2(userId : Int, sort : String, order : String){
viewModelScope.launch {
val response = repository.getCustomPosts2(userId,sort,order)
myCustomPosts2.value = response
}
}
아까와 같이 각각 인터페이스,저장소,뷰모델에 추가해준다.
binding.button.setOnClickListener {
val myNumber = binding.editTextView.text.toString()
viewModel.getCustomPosts2(Integer.parseInt(myNumber),"id","desc")
}
정렬 기준에 id, 순서는 내림차순으로 입력하였다.
아까와 달리 내림차순으로 출력되는 것을 확인할 수 있다.
https://jsonplaceholder.typicode.com/posts?userId=3&_sort=id&_order=desc
주소창에서 ?과 &을 이용하여 작성하면 동일한 결과를 확인할 수 있다.
위와 같은 다중쿼리를 쿼리맵으로 작성할 수 있는데,
@QueryMap 어노테이션을 사용하면 된다.
@GET("posts")
suspend fun getCustomPost3(
@Query("userId") userId : Int,
@QueryMap options : Map<String, String>
): Response<List<Post>>
suspend fun getCustomPosts3(userId : Int, options : Map<String, String>) : Response<List<Post>> {
return RetrofitInstance.api.getCustomPost3(userId,options)
}
val myCustomPosts3 : MutableLiveData<Response<List<Post>>> = MutableLiveData()
fun getCustomPosts3(userId : Int, option : Map<String, String>){
viewModelScope.launch {
val response = repository.getCustomPosts3(userId,option)
myCustomPosts3.value = response
}
}
각각 작성해준 후
val options : HashMap<String, String> = HashMap()
options["_sort"] = "id"
options["_order"] = "desc"
binding.button.setOnClickListener {
val myNumber = binding.editTextView.text.toString()
viewModel.getCustomPosts3(Integer.parseInt(myNumber),options)
}
해시맵 형태의 옵션 변수를 만들어 조건들을 할당해준다.
아까와 동일한 값이 출력되는 것을 확인할 수 있다.
https://github.com/HanYeop/AndroidStudio-Practice/tree/master/Retrofit_Test
참조
https://www.youtube.com/watch?v=Dw_BIR5K82Q&list=PLSrm9z4zp4mF1Ssdfuocy2XH5Bw4wLLNw&index=2