Retrofit 구조
1. Retrofit2
- Retrofit2는 Square사에서 만든 HTTP 통신을 위한 라이브러리
- 동작 원리
- Retrofit은 네트워킹을 위한 정보(url, request/response 데이터)를 어노테이션으로 주면 네트워킹을 하기 위한 실제 프로그램 코드는 자동으로 만들어준다
- 네트워크 관련 프로그램 코드를 작성하지 않아도 됨
- 위 그림처럼 개발자가 인터페이스를 만들고 Retrofit에 등록하면 Retrofit에서 인터페이스를 구현한 클래스를 자동으로 만들어 준다
- 이것을 호출하면 네트워킹이 가능한 Call 객체를 반환하고 Call 객체를 enqueue하면 그 순간에 네트워킹이 된다
2. Retrofit2 라이브러리 dependency 설정
1) dependency 작성
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이지만 개발자 선택에 따라 다른 parser를 선택해도 됨
- 'com.squareup.retrofit2:converter-gson'
- 위의 라이브러리에서 파싱한 것을 dto 객체로 바꿔주는 라이브러리
- parser로 gson을 선택했을 때 converter는 gson을 지원하는 것을 써야 함
- 최신 버전은 retrofit2과 동일하게 작성
2) 모델 클래스(dto 클래스, vo 클래스)
// JSON 데이터
{
"id": 7,
"email": "2minha721@gmail.com",
"first_name" : "Minha",
"last_name" : "Lee"
"avatar" : "https://tinyurl.com/3jnwvfu9"
}
data class UserListModel(
var id: String,
var email: String,
@SerializedName("first_name")
var firstName: String,
@SerializedName("last_name")
var lastName: String,
var avatar: String
)
- 모델 클래스(dto 클래스, vo 클래스)란 서버와 주고 받는 데이터를 표현하는 클래스
- parser와 converter로 JSON, XML 데이터를 파싱해 모델 클래스 객체에 담아주는 것이 자동화
- JSON 데이터를 모델 클래스에 담을 때 어느 변수에 담는지를 어떻게 판단하냐?
- 기본적으로 JSON의 key값과 동일한 이름의 변수에 담음
- 다른 경우 @SerializedName 어노테이션을 사용해서 매칭
3) parser 종류
- Gson : com.squareup.retrofit2:converter-gson
- 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
Retrofit 활용
1. 서비스 인터페이스
interface INetworkService {
@GET("api/users")
fun doGetUserList(@Query("page") page: String): Call<UserListModel>
}
- 네트워크 통신에 이용될 인터페이스로 네트워크 통신이 필요한 순간 호출할 함수를 선언만 한다
- 어노테이션을 통해 서버와 통신할 HTTP 방식을 지정하고 base URL 뒤에 들어가는 path 정보를 준다
- 서버에 request할 때 넘겨야할 값이 있다면 @Query("key값") value값: type 형식으로 함수의 매개변수로 작성한다
- 반환 값은 Call객체로 Call객체가 enqueue되면 네트워킹이 실행
- Call객체의 제네릭 타입은 개발자가 만든 DTO 객체
- 서버 통신을 통해 리턴 받은 데이터를 제네릭 타입으로 지정한 DTO 객체에 담아준다
2. Retrofit 객체
val retrofit: Retrofit
get() = Retrofit.Builder()
.baseUrl("https://reqres.in/")
.addConverterFactory(GsonConverterFactory.create())
.build()
- Retrofit의 초기 설정을 목적
- 애플리케이션이 실행되면서 최초에 한 번 실행되는 곳에 작성하는 것이 일반적
- baseUrl() 함수를 이용해서 서버 연동을 위한 base URL 설정
- addConverterFactory() 함수를 이용해 converter 지정
- 이 외에도 로그, 보안 등과 관련한 설정을 할 수 있음
3. 인터페이스 구현 객체 획득
var networkService: INetworkService = retrofit.create(INetworkService::class.java)
- Retrofit 객체를 이용해 실제 네트워킹에 이용할 인터페이스를 구현한 클래스의 객체를 획득
- 이후에 프로그램에서 이 객체를 이용해 인터페이스의 함수를 호출하면 Call 객체가 리턴
4. 네트워킹
val userListCall = networkService.doGetUserList("1")
userListCall.enqueue(object: Callback<UserListModel> {
override fun onResponse(call: Call<UserListModel>, response: Response<UserListModel>) {
val userList = response.body()
}
override fun onFailure(call: Call<UserListModel>, t: Throwable) {
call.cancel()
}
})
- 3의 과정으로 획득한 객체에서 함수를 콜하면 Call 객체가 리턴된다
- 리턴 받은 Call 객체를 enqueue하는 순간 실제 네트워킹이 된다
- 통신 성공여부에 따라 결과값을 획득하기 위해 매개변수에 Callback 사용, onResponse와 onFailure는 Callback의 함수
- onResponse는 네트워킹이 성공해서 서버로부터 데이터를 정상적으로 받은 순간 호출
- 매개변수는 서버로부터 response 받는 데이터임
- 매개변수의 제네릭 타입으로 우리가 만든 DTO객체 설정
- 서버로부터 response 받은 매개변수를 이용해서 안드에서 사용
- onFailure는 네트워킹이 실패했을 때 호출
Glide로 이미지 다운로드
1. Glide
implementation 'com.github.bumptech.glide:glide:버전'
- 구글에서 만든 이미지 핸들링을 위한 라이브러리
- Retrofit도 이미지 다운로드가 가능하지만, Glide는 이미지만을 위한 전문 라이브러리
- 이미지 다운로드에는 Retrofit보다 Glide를 사용하는 것이 훨씬 쉽다
- 네트워크만을 위한 것이 아니라 크기 조정 등 다양한 핸들링도 가능한 라이브러리
- 리소스 이미지, 파일 이미지, 네트워크 이미지 획득
- 이미지의 크기 조정
- 로딩 이미지 표시
- 에러 이미지 표시
- 최신 버전은 https://github.com/bumptech/glide 에서 확인 가능
2. Glide 사용 방법
1) 이미지를 ImageView에 출력
Glide.with(this)
.load(R.drawable.seoul)
.into(resultView)
Glide.with(this)
.load(url)
.into(resultView)
2) 특정 크기로 이미지가 로딩
Glide.with(this)
.load(R.drawable.seoul)
.override(200, 200)
.into(resultView)
- 파일 이미지나 서버로부터 받는 이미지는 데이터 이미지여서 사이즈 때문에 OOM 문제가 발생할 수 있음
- override로 사이즈 조정
3) 로딩, 에러 이미지 출력
Glide.with(this)
.load(url)
.override(200, 200)
.placeholder(R.drawable.loading)
.error(R.drawable.error)
.into(resultView)
- placeholder는 로딩 상황에 뜨고 서버 이미지가 다운로드 되는 순간 교체
- error는 에러 상황에 뜸