며칠 전 업로드한 Asynctask 방식 대신 Retrofit2 이라는 Square사에서 제공하는 오픈소스 라이브러리를 사용하여 구현해보았다.  처음 사용해 본 오픈소스라 약간 낯설었지만, 조금 익숙해지니 기존 방식보단 더 편한거 같기도 ,,?

xml 파싱에  SimpleXmlConverterFactory 를 사용했지만, 이것도 ..  deprecated 되었다고 하니  다른 분들은 JAXBConverter 를 사용하시는 걸 추천 !! 

 

 

 

내가 생각하기에 REST API는 요청 값이랑 받아오는 리턴 형식만 잘 맞추면 큰 무리 없이 기능 완성이 가능한 거 같다.

꼭꼭 사용하고자 하는 api의 요청 변수 값을 제대로 넣어줘야 사용이 가능하니 체크 하기  

 

 

오늘 목표 : 위치 기준으로 전국 약국 조회하기 

 

전체 URL = apis.data.go.kr/B552657/ErmctInsttInfoInqireService/getParmacyLcinfoInqire?ServiceKey="본인 서비스 키"&WGS84_LON=" " &WGS84_LAT=" "

 


[ 요청시 반환되는 xml 파일 형식 ]

 


 

 

1. permission과 dependencies 설정하기 

 

retrofit2과 converter를  버전을 맞춰서 넣기 

또한 통신을 위해서 Manifest에 internet permission을 넣어주기 

 

 

2.  Retrofit API 설정하기 ( interface )

interface RetrofitAPI{  //  data를 얻기 위한 retrofitAPI
    @GET("getParmacyLcinfoInqire?")
    fun getPharmacy(@Query("ServiceKey") ServiceKey:String,
                    @Query("WGS84_LON") WGS84_LON:Double,
                    @Query("WGS84_LAT") WGS84_LAT:Double)
            : Call<SearchResponseWrapper>

}

@Query로 요청할 때 필요한 변수들의 이름을 넣어주면 된다.  

 

 

3.  값을 받는 POJO 클래스 정의하기 

 

@Root(name="response")
class SearchResponseWrapper @JvmOverloads constructor(
    @field:Element(name="header")
    var header:GetHeader? =null,
    @field:Element(name="body")
    var body:SearchResponse? = null

)
@Root(name="header")
class GetHeader @JvmOverloads constructor(
    @field:Element(name="resultCode")
    var resultCode:String ="",
    @field:Element(name="resultMsg")
    var resultMsg:String = ""
)

@Root(name= "body")
class SearchResponse @JvmOverloads constructor(
    @field:Element(name="items")
    var items:ResponseItme? =null,
    @field:Element(name="numOfRows")
    var numOfRows:String? =null,
    @field:Element(name="pageNo")
    var pageNo:String? = null,
    @field:Element(name = "totalCount")
    var totalCount:String? = null
)
@Root(name="items")
class ResponseItme @JvmOverloads constructor(
    @field:ElementList(inline = true)
    var item:List<Item>?=null
)
@Root(name="item")
class Item @JvmOverloads constructor(
    @field: Element(name = "cnt")
    var cnt:String ="",
    @field: Element(name = "distance")
    var distance:String ="",
    @field: Element(name = "dutyAddr")
    var dutyAddr:String ="",
    @field: Element(name = "dutyDiv")
    var dutyDiv:String ="",
    @field: Element(name = "dutyDivName")
    var dutyDivName:String ="",
    @field: Element(name = "dutyFax",required = false)
    var dutyFax:String ="",

    @field: Element(name = "dutyName")
    var dutyName:String= "",
    @field: Element(name = "dutyTel1")
    var dutyTel1:String = "",

    @field: Element(name = "endTime")
    var endTime:String ="",

    @field: Element(name = "hpid")
    var hpid:String ="",
    @field: Element(name = "latitude")
    var latitude:String ="",
    @field: Element(name = "longitude")
    var longitude:String ="",
    @field: Element(name = "rnum")
    var rnum:String ="",
    @field: Element(name = "startTime")
    var startTime:String =""


    )

json 의 POJO 클래스 예시는 많았지만, xml 예시는 거의 없어서 내가 직접 올린다. 정말 많은 구글링 끝에 발견 ㅠㅠ 

xml은 Element (name = 변수 이름 ) 을 넣어주면 된다. 이때 변수 이름은 반환 받은 변수의 이름과 정확히 일치해야 하며 반환 되는 부분의 변수를 모두 넣어줘야 제대로  값을 받을 수 있다 !!!!

 

반환되는 item 마다 어떤 변수는 들어있고, 없고 하는 경우가 있다. 이런 경우에   required = false를 넣어주면 된다.

 

 

 

4. Builder 설정

fun setRetrofitInit() {
        retrofit = Retrofit.Builder()
            .baseUrl("http://apis.data.go.kr/B552657/ErmctInsttInfoInqireService/")
            .addConverterFactory(SimpleXmlConverterFactory.create())
            //.client(createOkHttpClient())
            .build()
        retrofitService = retrofit.create(RetrofitAPI::class.java)

    }

나는 따로 함수를 만들어서 Bulider를 설정했다.

baseUrl부분은 바뀌지 않는 url까지 넣어주면 된다. 

 

 

 

5. Client 객체 만들고 통신 & 응답 처리 

 

fun callProduct() {
        retrofitService.getPharmacy(ServiceKey,log!!,lan!!)
            .enqueue(object : retrofit2.Callback<SearchResponseWrapper> {


                override fun onResponse(
                    call: Call<SearchResponseWrapper>,
                    response: retrofit2.Response<SearchResponseWrapper>
                ) {
                    val body = response.body()
                    Log.d("data", body)
                    
                }

                override fun onFailure(call: Call<SearchResponseWrapper>, t: Throwable) {
                    Log.d("fail", t.message.toString())
                }
            })


    }

제대로 데이터를 긁어온 것을 확인 할 수 있을 것이다.

참고로 나는 xml 형식으로 파싱 받은 데이터 처리 부분에 고민하다가 아무리 생각해도 모르겠어서 그냥 반환 데이터를 json으로 변환한 후 필요한 정보만  arrayList에 넣어서 fragment에 띄워줬다.  제대로 작동되긴 하지만 코드에 자신이 없어서 그 부분은 일단 제외하고 업로드를 했다.

          ->  제가 했던 방식 외에 더 좋은 방식의 자료가 있다면 추천 부탁드립니다 ! 

 

 


 

 

 

[결과]

 

 

 

현재 위치를 기반으로 알아서 가장 가까운 약국부터 순서대로 데이터가 들어온다.  파일 데이터 였으면 추가로 위도 경도 별로 거리 계산 함수를 만든 뒤 정렬해서 데이터를 뿌려줬어야 하지만,  알아서 거리 순서대로 정렬되어 데이터가 들어오니 정말 편리 한거 같답  

 

전체 코드는 어플이 완성되면 깃허브에 업로드 할 예정이다 

 

 

+ Recent posts