그동안 서버 데이터 불러오기 작업을 하면서 AsyncTask를 통해 백그라운드 처리를 하고 HttpURLConnection객체를 사용해 API매핑을 하였습니다. 긴 코드와 재활용할 수 있어 보이는 코드를 보며 서버 요청 라이브러리가 있으면 좋을 것 같다는 생각을 하였는데 아니나 다를까 많이 들어보던 Retrofit이라는 라이브러리가 바로 그것이었습니다.
오늘은 Retrofit을 통하여 서버에서 데이터 요청을 하고 커스텀 객체에 적용하는 실습을 진행해보도록 하겠습니다.
우선 gradle 종속성을 추가합니다.
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
그런 뒤에 Retrofit으로 통신할 URL을 등록하고
<string name="databaseUrl">your database url</string>
<strings.xml>
커스텀할 RetrofitAPI 인터페이스를 추가합니다.
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface RetrofitAPI {
@GET("/your data path")
fun getProducts(@Query("your param1") param1:Int, @Query("your param2") param2:String):Call<ProductResponse>
}
인터페이스에 path와 추가할 param은 서버에서 정의한 형식대로 작성해 주시면됩니다.
그런 뒤에 서버 요청을 할 엑티비티 또는 뷰에서 다음과 같은 속성을 추가합니다.
var products:List<Product>? = null
var callProducts:Call<ProductResponse>? = null
private lateinit var retrofit:Retrofit
private lateinit var retrofitAPI:RetrofitAPI
생명 주기에 따라 oncreate 또는 oncreateview에서 다음 메소드를 호출하여 초기화를 수행합니다.
fun setRetrofiInit(){
retrofit = Retrofit.Builder()
.baseUrl(getString(R.string.databaseUrl))
.addConverterFactory(GsonConverterFactory.create())
.build()
retrofitAPI = retrofit.create(RetrofitAPI::class.java)
}
fun callProducts(){
callProducts = retrofitAPI.getProducts(pageNum, type)
callProducts?.enqueue(retrofitCallback)
}
Retrofit을 통하여 데이터 요청이 완료되었을 경우 수행하는 view작업을 위한 listener를 등록하기 위하여 retrofitCallback을 정의합니다.
val retrofitCallback = object:Callback<ProductResponse>{
override fun onFailure(call: Call<ProductResponse>, t: Throwable) {
t.printStackTrace()
}
override fun onResponse(call: Call<ProductResponse>, response: Response<ProductResponse>) {
val result = response.body()
productResponse = result
if(productResponse != null){
products = productResponse?.body
connectionListener.responseEnd()
}
}
}
여기까지 완료가 되었다면 요청한 데이터를 입력할 객체를 생성합니다.
보통 서버 요청에 대한 body로는 responsecode, data(원하는 값), flag와 같은 형태로 출력되는 관계로 productResponse라는 클래스와 실제 원하는 데이터인 product클래스를 생성합니다.(여러분이 원하는 데이터 형식대로 맞춰주면 됩니다.)
여기서 주의할 점은 정의한 클래스의 변수명과 서버에서 가져오는 key값이 정확히 같아야 한다는 점입니다.
만약 다르다면 'Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $' 이런 형식의 예외가 발생합니다.
class Product(){
var id = 0
var price:String? = null
var oily_score = 0
var dry_score = 0
var sensitive_score = 0
var thumbnail_image:String? = null
var title:String? = null
}
<Product.kt>
class ProductResponse{
var statusCode = 0
var body:List<Product>? = null
var scanned_count = 0
}
<ProductResponse.kt>
여기까지 하면 복잡한 데이터 요청과 Json파싱을 모두 생략한 채로 Retrofit라이브러리가 모든 작업을 수행해줍니다.(정말 간단하죠 ??)
connectionListener의 경우 원하는 view작업을 수행할 리스너를 커스텀 하시면 되겠습니다.
connectionListener와 Retrofit을 적용하지 않고 데이터를 불러오는 실습은 아래에 있습니다.(객체 형식이 다르니 주의하세요!!Skin -> Product)
https://in-idea.tistory.com/22
이상으로 Retrofit을 적용한 데이터 요청에 대한 포스팅을 마치겠습니다.
궁금하신 점이 있다면 편하게 댓글 남겨 주시면 감사하겠습니다 :)
'IT 프로그래밍-Android' 카테고리의 다른 글
안드로이드 라이브러리 bintray 배포 시 주의할 점 (0) | 2020.03.18 |
---|---|
[안드로이드] Viewpager와 indicator를 한번에 !! (0) | 2020.03.17 |
[Android] RecyclerView 무한스크롤(endless scroll) 만들기 (0) | 2020.01.16 |
[Android] Glide 라이브러리 gif파일 로드 (0) | 2020.01.10 |
[Android] 서버에서 데이터 불러오기 (0) | 2019.12.23 |