안드로이드) Retofit 정리(GET 방식 1)

Retrofit 이해한 기념.. Retrofit 이해한 지금의 내가 까먹었을 지도..? 모를 미래의 나를 위해 바치는 글입니다...
개념이나 간단한 정리는 아래의 글을 참고해주세요.
https://velog.io/@alsgk721/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-21-Network-Library


0. 완성본

https://github.com/minha721/android-practice/tree/main/retrofit-get

이 예제는 github api를 이용해서 TextView에 github id를 입력하면 해당 id 유저의 프로필 사진, 이름, id, 레포지토리 갯수를 출력한다


1. 퍼미션, Gradle 의존성 추가

1) 퍼미션 추가

  • manifests.xml의 manifest 태그 하위에 인터넷 퍼미션을 추가한다.
<uses-permission android:name="android.permission.INTERNET"/>

2) Gradle 의존성 추가

  • 모듈 단위 build.gradle에 의존성을 추가한다.
implementation 'com.squareup.retrofit2:retrofit:버전'
implementation 'com.google.code.gson:gson:버전'
implementation 'com.squareup.retrofit2:converter-gson:버전'
  • com.square.retrofit2.retrofit
  • com.google.code.gson:gson
    • 서버에서 받은 JSON, XML 데이터를 파싱하기 위한 라이브러리
    • 개발자 선택에 따라 다른 parser를 선택해도 된다.
      • Jackson : com.squareup.retrofit2:converter-jackson
      • Moshi : com.squareup.retrofit2:converter-moshi
      • Protobuf : com.squareup.retrofit2:converter-protobuf
      • Wire : com.squareup.retrofit2:converter-wire
      • Simple XML : com.squareup.retrofit2:converter-simplexml
      • JAXB : com.squareup.retrofit2:converter-jaxb
      • Scalars(primitives, boxed, String) : com.squareup.retrofit2:converter-scalars
    • 최신 버전은 https://github.com/google/gson 에서 확인할 수 있다.
      • (2022.02.12 기준 2.9.0)
  • com.squareup.retrofit2:converter-gson
    • gson 라이브러리에서 파싱한 것을 dto 객체로 바꿔주는 라이브러리
    • parser로 gson을 선택했을 때 converter는 gson을 지원하는 것을 써야 한다.
    • 최신 버전은 retrofit2과 동일하게 작성한다.

2. 네트워킹을 위한 세팅

1) DTO 클래스 생성 (User.kt)

  • 서버와 주고 받는 데이터를 표현하는 DTO 클래스를 생성한다.
// JSON 데이터
{
    "avatar_url": "https://avatars.githubusercontent.com/u/49333608?v=4",
    "name": "Minha Lee",
    "login": "minha721",
    "public_repos": 15
}   
// DTO 클래스
data class User(
    @SerializedName("avatar_url")
    var image: String = "",
    var name: String = "",
    @SerializedName("login")
    var userId: String = "",
    @SerializedName("public_repos")
    var repos: Int = 0)
  • parser와 converter가 JSON이나 XML 데이터를 파싱해 DTO 객체에 담아주는 것을 자동화해준다.
    • 이 과정에서 기본적으로 JSON의 key값과 동일한 이름의 변수에 데이터를 담지만, 다른 경우 @SerializedName 어노테이션을 사용해서 매칭한다.

2) Retrofit 객체 생성 (GithubService.kt)

  • Retrofit 객체를 생성해 초기 설정을 한다.
object GithubService {
    val retrofit: Retrofit
        get() = Retrofit.Builder()
            .baseUrl("https://api.github.com/users/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    ...
}
  • baseUrl()을 이용해 서버 연동을 위한 base URL을 설정한다.
    • base URL은 호출하는 주소의 고정값으로 세팅하면 URL 호출 시 반복을 줄여주는 역할을 한다.
  • addConverterFactory() 함수를 이용해 converter를 지정한다.
  • 이 외에도 필요에 따라 여러 설정들을 하면 된다.

3) 서비스 인터페이스 생성 (IGithubService.kt)

  • 네트워크 통신에 이용될 인터페이스로 네트워크 통신이 필요한 순간 호출할 함수를 선언만 한다.
interface IGithubService {
    @GET("{userId}")
    fun requestUserInfo(@Path("userId") userId: String): Call<User>
}
  • 어노테이션을 통해 서버와 통신할 HTTP 방식을 지정하고 base URL 뒤에 들어가는 path 정보를 준다.
  • 함수의 매개변수에는 request할 때 넘겨야 하는 값을
    @어노테이션("key값") value값: type 형식으로 작성한다.
    • 데이터를 넘길 때 path variable을 사용하는 경우 @Path를 사용한다.
      • api.github.com/users/{userID}
    • 데이터를 넘길 때 query parameter를 사용하는 경우 @Query를 사용한다.
      • api.github.com/users?userId=
  • 반환 값은 Call 객체로 제네릭 타입은 전단계에서 생성한 DTO 객체이다.

4) 인터페이스 구현 객체 획득 (GithubService.kt)

  • Retrofit 객체를 이용해 실제 네트워킹에 이용할 인터페이스 구현 객체를 획득한다.
object GithubService {
    ...
    var service: IGithubService = retrofit.create(IGithubService::class.java)
}

5) 인터페이스 구현 객체의 함수 호출 (GithubAPI.kt)

  • 실제 네트워킹에 이용할 클래스의 객체를 호출해 Call 객체를 리턴한다.
object GithubAPI {
    fun requestUserInfo(userId: String): Call<User> {
        return GithubService.service.requestUserInfo(userId)
    }
}

3. 네트워킹

1) 변수 선언 (UserViewModel.kt)

  • 서버에서 데이터를 받아 안드로이드에서 사용할 변수를 선언
class MainViewModel: ViewModel() {
    val okCode: MutableLiveData<Boolean> = MutableLiveData()
    lateinit var userData: User
    ...
}
  • Activity에서 LiveData의 변경을 감지해서 데이터를 준비하기 위해 네트워킹의 성공 여부를 체크하는 okCode 변수 선언
  • User 정보를 받아 화면에 출력하기 위한 userData 변수 선언

2) Call 객체 enqueue (UserViewModel.kt)

  • 2-5 단계에서 만든 함수를 호출하면 Call 객체가 리턴, 이 Call 객체를 enqueue하는 순간 실제 네트워킹이 된다.
class MainViewModel: ViewModel() {
    ...
    fun requestUserInfo(userId: String) {
        GithubAPI.requestUserInfo(userId).enqueue(object: Callback<User> {
            override fun onResponse(call: Call<User>, response: Response<User>) {
                userData = response.body()?.let {
                    User(
                        image = it.image,
                        name = it.name,
                        userId = it.userId,
                        repos = it.repos
                    )
                } ?: User("", "", "", 0)
                okCode.value = true
            }

            override fun onFailure(call: Call<User>, t: Throwable) {
                okCode.value = false
                Log.d("minha - MainViewModel", "${t.message}")
            }
        })
    }
}
  • 성공 여부에 따라 결과값을 획득하기 위해 매개변수에서 Callback을 사용한다.
    • onResponse는 Callback의 함수로 네트워킹이 성공해서 서버로부터 데이터를 정상적으로 받은 순간 호출된다.
      • 함수 내부에서 전단계에서 선언한 데이터들에 값을 대입한다.
    • onFailure는 네트워킹이 실패했을 때 호출된다.

3) 네트워킹이 시작되는 함수를 실행 (MainActivity.kt)

  • ViewModel 객체를 생성해서 네트워킹이 시작되는 함수를 실행한다. (MainActivity.kt)
private fun callGithubAPI(userId: String) = mainViewModel.requestUserInfo(userId)

4) liveData observe해서 데이터 세팅 (MainActivity.kt)

  • liveData인 okCode를 observe해서 액티비티에 출력할 데이터를 세팅한다.
private fun subscribeViewModel() {
        mainViewModel.okCode.observe(this){
            if(it) {
                val userData = mainViewModel.userData

                if(userData.userId != "") {
                    showInfoViews()
                    Glide.with(this).load(userData.image).override(150, 150).into(binding.ivImage)
                    binding.tvName.text = userData.name
                    binding.tvId.text = userData.userId
                    binding.tvRepos.text = userData.repos.toString()
                } else {
                    Toast.makeText(this, "입력하신 ID는 존재하지 않습니다. 다시 시도해주세요.", Toast.LENGTH_SHORT).show()
                }

            } else {
                Toast.makeText(this, "입력하신 ID의 상세 정보 조회를 실패했습니다. 다시 시도해주세요.", Toast.LENGTH_SHORT).show()
            }
        }
    }

Outro

  1. 네트워킹을 하기 위해 퍼미션과 의존성을 추가한다.
  2. Retrofit 객체를 생성해 초기 설정을 한다.
  3. 네트워크 통신에 이용할 함수의 인터페이스를 생성한다.
  4. 생성한 retrofit 객체를 이용해 네트워크 통신에 이용할 인터페이스 구현 객체를 획득한다.
  5. 실제 네트워킹에 이용할 클래스의 객체를 호출해 Call 객체를 리턴한다.
  6. Call 객체를 enqueue해 네트워킹을 시작하는 함수를 만든다.
  • onResponse는 네트워킹이 성공했을 때 실행 → 안드에서 사용할 변수에 서버에서 받아온 데이터를 세팅하는 작업 등을 하면 됨
  • onFailure는 네트워킹이 실패했을 때 실행
  1. 네트워킹을 시작하는 함수를 호출해서 액티비티에 데이터를 세팅한다.

좋은 웹페이지 즐겨찾기