[안드로이드 코드랩] Android Kotlin Fundamentals:8.1 Getting data from the internet (1)

홍석규·2022년 2월 20일
0

안드로이드 코틀린 기초 코드랩을 학습한 내용입니다.
https://developer.android.com/courses/kotlin-android-fundamentals/overview?hl=ko

Explore the MarsRealEstate starter app

이번 코드랩에서 사용 할 MarsRealEstate 앱에 대한 구조를 살펴보자.

  • overview Fragment는 이미지들을 썸네일로 보여주는 RecyclerView 형태다.
  • detail ViewFragment는 각 속성들을(썸네일 이미지를) 클릭 했을 때 상세 내용을 보여준다.
  • 각 Fragment마다 별도의 ViewModel을 가지고 있고 OverView ViewModel의 경우 Retrofit Service를 이용해 서버와 api 통신을 진행한다.
  • 이전 코드랩에서 진행 했던것과 유사하게(Room 사용 내용) Overview ViewModel에서 직접 Retrofit Service를 참조해서 api 호출을 진행한다.
  • overview ViewModel은 Mars real estate 정보를 받는 api를 호출하는 책임을 가지고 있고 details ViewModel은 detail fragment에서 보여줘야 할 detail property에 대한 정보를 저장하는 책임을 진다.
private val viewModel: OverviewViewModel by lazy{
ViewModelProvider(this).get(OverviewViewModel::class.java)
}
  • viewModel을 처음 사용하는 시점에 초기화 하겠다는 by lazy 패턴 적용

Connect to a web service with Retrofit

  • init() 단계에서 임의로 넣어준 string value는 실제 서버 api를 호출 해서 받아와야한다. 본 단계에서 해당 과정을 진행 할 예정이다.
https://android-kotlin-fun-mars-server.appspot.com
  • 본 앱에서 위 URI로부터 데이터를 받아 올 것이다.
  • restapi 의 응답값은 key-value 타입의 json 형태로 받아오게 되는데 app에서 해당 데이터를 사용하기 위해선 서버호출 - 응답 - json data parse 과정을 거쳐야 한다.
  • 이번 코드랩에선 REST client library로 Retrofit을 사용 할 것이다.

app gradle 파일에 retrofit 의존성을 추가해주자.

implementation "com.squareup.retrofit2:retrofit:$version_retrofit"
    implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"

Implement MarsApiService

  • 레트로핏은 web service 콘텐츠를 기반으로 앱에대한 네트워크 api를 만들어준다.
  • 레트로핏은 서버로부터 데이터를 가져와서 data를 decode하는 convert 과정을 거쳐 사용가능한 객체의 형태로 반환해준다.
  • 레트로핏은 XML, JSON과 같은 유명한 웹 데이터 포맷들에 대해 지원해준다.
  • 백그라운드 쓰레드에서 요청하는 것과 같은 중요한 세부 정보들을 포함해서 네트워크 계층의 대부분 내용을 생성한다.
private val retrofit = Retrofit.Builder()
		.addConverterFactory(ScalarsConverterFactory.create())
    .baseUrl(BASE_URL)
		.build()

레트로핏을 사용하기 위해 적어도 2가지가 준비 되어야한다. web service를 위한 base url, 그리고 converter factory . converters는 레트로핏에게 웹 서버로부터 받은 데이터로 무엇을 해야하는지 알려줄 수 있다.

interface MarsApiService {
    @GET("realestate")
    fun getProperties():
            Call<String>
}
  • 레트로핏이 사용할 method를 정의해준다. interface타입으로 정의 해주면 어노테이션 프로세서가 컴파일 타임에 구현체로 구현 해준다. 사용자가 전달 해 줄 내용은 어떤 http method를 사용할 것인지, 어떤 타입으로 반환 해줄지를 정하는것 이다.
  • GET 메서드를 사용하고 “realestate” 를 어노테이션 파라미터로 넣어줬는데 realestate를 base url의 endpoint에 추가 하라는 의미다.
  • 이렇게 정의 해주면 retrofit이 base url에 realestate를 추가하고 Call 객체를 생성해준다. Call 객체는 request를 시작하기 위해 사용하는데 refrofit 인터페이스 설명을 잘 보면 각 call yields는 자신의 http reqeust, response 쌍을 가지고 있다고 한다.

rest api 메서드를 interface에 정의 해줬다면 이제 생성하는 코드를 만들어 줘야한다.

object MarsApi {
    val retrofitService: MarsApiService by lazy {
        retrofit.create(MarsApiService::class.java)
    }
}
  • Retrofit Builder 패턴을 이용해 생성한 retrofit의 create메서드를 호출하면서 파라미터로 interface를 넘겨준다. 이렇게 하면 인터페이스 기반으로 메서드를 만들어서 retrofit을 사용할 수 있게 되는 것이다.
  • retrofit.create를 호출하는 과정은 리소스가 많이 들기 때문에 Retrofit service를 lazily initialize 해주었다. 그리고 앱은 1개의 Retrofit service 객체가 필요하기 때문에 MarsApi라는 object를 이용해서 서비스를 앱 전체에서 사용할 수 있게 처리해준다.
  • 이제 셋업이 완료 되고 MarsApi.retrofitService를 호출 하면 MarApiService를 구현한 단일 객체가 매번 반환 될 것이다.

Retrofit method 호출하기 (callback 이용)

윗 단계까지 retrofit을 이용한 메서드를 정의 했는데 실제로 사용 해보자. OverviewViewModel에서 retrofit service를 바로 호출하는 구조를 가지고 있으며 viewModel의 getMarsRealEstateProperties()에서 api 호출 로직을 추가한다.

MarsApi.retrofitService.getProperties().enqueue(
            object: Callback<String> {
                override fun onResponse(call: Call<String>, response: Response<String>) {
                    TODO("Not yet implemented")
                }

                override fun onFailure(call: Call<String>, t: Throwable) {
                    TODO("Not yet implemented")
                }
            })
  • getProperties()를 호출하면 해당 메서드는 Call 객체를 반환한다. Call 객체의 enqueue 메서드를 통해서 비동기 요청을 전달하고 요청의 응답 값을 Callback 구현체를 통해 넘겨받을 수 있게 된다.
  • enqueue()메서드를 호출 하게되면 network request과정이 자동으로 background thread에서 진행 된다.

API 호출이 정상적으로 잘 끝나면 onResponse 콜백 메서드가 호출되면서 응답값이 response 파라미터를 통해 들어오게 될 것이다.

API 호출이 정상적으로 끝나지 않는다면 onFailure 콜백 메서드가 호출되면서 응답 실패의 원인이 에러 객체로 파라미터를 통해 들어오게 된다.

이대로 앱을 빌드하고 실행하면 앱 크래시가 나버린다.

  • 인터넷에 연결하면 보안 문제가 발생해서 기본적으로 앱은 인터넷에 연결 되는것을 허용하지 않는다. 그래서 안드로이드에게 명시적으로 이를 알려줘야한다.

AndroidManifest.xml 파일을 열어 다음 줄을 추가해준다.

<uses-permission *android:name*="android.permission.INTERNET" />

  • 앱을 다시 빌드하고 실행 했을 경우 잘 동작한다면 위의 api response가 json text형태로 잘 나오는것을 알 수 있다. 이제 해당 json값을 잘 파싱해서 앱을 이어서 만들어보자.
profile
학습한 내용을 공유하고 기록합니다.

0개의 댓글