Retrofit은 HTTP API를 Java 인터페이스로 변환해주는 타입 안전한 HTTP 클라이언트 라이브러리이다.
즉, RESTful API와의 통신을 간단하고 효율적으로 만들어주는 것을 목표로한다.
Retrofit은 선언적인 방식으로 API를 정의하고, HTTP 요청과 응답을 위한 인터페이스 기반의 선언적인 방식을 제공한다.
이를 구현하여 네트워크 요청을 손쉽게 처리할 수 있게 해준다.
안드로이드 앱 개발에서는 UI를 변경하거나 갱신하는 작업은 메인 스레드(또는 UI 스레드)에서만 수행해야 한다.
그러나 네트워크 작업, 대용량 데이터 처리, 복잡한 계산과 같은 시간이 많이 소요되는 작업은 메인 스레드에서 실행하면 앱이 느려지거나 "응답 없음(ANR)" 오류가 발생할 수 있다.
과거에는 AsyncTask가 위와 같은 패턴을 구현하는 데 자주 사용되었지만, 더 이상 권장되지 않으며 안드로이드 11부터는 사용이 중지되었다.
Retrofit은 내부적으로 비동기적인 네트워크 요청을 처리하고, 결과를 쉽게 메인 스레드로 전달할 수 있는 구조를 가지고 있어, 복잡한 스레드 관리 없이도 안드로이드 앱에서 효율적인 네트워크 통신을 구현할 수 있게 해준다.
Retrofit과 비동기 처리의 연관성
- 백그라운드 스레드에서의 네트워크 요청
네트워크 호출은 자동으로 백그라운드 스레드에서 수행된다.
이것은 개발자가 직접 스레드를 관리하거나 별도의 비동기 처리 매케너즘을 구현할 필요가 없음을 의미한다. - 메인 스레드에서의 UI 업데이트
네트워크 요청의 결과를 받아 콜백을 통해 메인 스레드로 전달한다.
이 콜백은 앱의 생명주기와 연결되어 있어 네트워크 요청의 결과를 받는 즉시 UI 업데이트를 할 수 있다.
예를 들어, Retrofit의 enqueue 메소드를 사용하면 네트워크 응답을 비동기적으로 처리하고, 응답이 도착하면 메인 스레드에서 실행되는 콜백(onResponse 또는 onFailure) 내에서 UI를 업데이트할 수 있다.
통신과정
Client ( okHttp )
Retrofit 내부에는 okHttp 클라이언트를 사용해서 실제 HTTP 통신을 처리한다.
OkHttp는 효율적인 HTTP & HTTP/2 지원을 제공하는 또 다른 Square의 라이브러리로, 빠르고 신뢰성 있는 네트워크 통신을 가능하게 한다.
Retrofit을 사용할 때 OkHttp 클라이언트는 자동으로 통합되며, 필요한 경우 개발자가 직접 OkHttp 클라이언트를 커스터마이징할 수도 있다.
- 요청 생성
Retrofit 인터페이스를 정의 / HTTP 요청의 세부사항(경로, 메소드, 매개변수)을 어노테이션을 통해 지정함 - Retrofit 설정
Retrofit 빌더를 사용하여 기본 URL, 컨버터 팩토리(Gson, Jackson...), 클라이언트(okHttp) 등을 설정 - 요청 실행
정의된 인터페이스를 통해 네트워크를 요청 실행 / Retrofit은 내부적으로 okHttp 클라이언트를 사용해서 서버로 전송 - 응답 처리
서버로 응답을 받으면, Retrofit은 설정된 컨버터 팩토리를 사용하여 응답을 자바 객체로 변환하고, 콜백 메소드를 통해 개발자에게 전달한다.
구성요소
- DTO ( Data Transfer Object )
서버와 클라이언트 간의 데이터 교환을 위해 사용되는 객체 ( ex : JSON 형태를 -> 자바 객체로 변환 ) - Interface
사용할 HTTP CRUD 동작들을 정의해놓은 인터페이스
각 메소드는 RESTful의 엔드포인트와 매핑되며, 어노테이션을 사용해서 메소드, 경로, 매개변수를 지정한다. - Retrofit.Builder
Retrofit 인스턴스를 생성하기 위한 빌더 클래스
Retrofit 클라이언트의 구성을 커스터마이징 할 수 있다.
기본 사용법 및 구현
1. 인터넷 권한 설정
<uses-permission android:name="android.permission.INTERNET" />
2. Gradle 의존성 추가 / 라이브러리 등록
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
※ 특정 요구 사항에 따라 추가 설정 해야함
3. API 정의
서버에서 제공하는 RESTful API의 엔드포인트를 정의한다.
실습에서는 ItemList 안에 Title, company, date, url 데이터가 존재하는 JSON 파일을 받아와 뉴스를 출력해보도록 하자.
4. DTO 데이터모델 설계
네트워크 응답을 모델링할 클래스를 설계한다. 응답에서 사용할 각 필드를 정의하면 된다.
또한 JSON 파일을 객체로 받아오는 것이 아니라 배열 형태로 받아와야 하기 때문에 맞춰서 getter를 추가로 정의해준다.
// Api_NewsItem.java
public class Api_NewsItem {
private String title;
private String company;
private String date;
private String url;
public Api_NewsItem(String title, String company, String date, String url) {
this.title = title;
this.company = company;
this.date = date;
this.url = url;
}
public String getTitle() { return title; }
public String getCompany() {
return company;
}
public String getDate() {
return date;
}
public String getUrl() {
return url;
}
}
// Api_Response.java
import java.util.List;
public class Api_Response {
private List<Api_NewsItem> itemList; // "itemList" 키 아래 있는 배열에 해당
// itemList의 getter
public List<Api_NewsItem> getItemList() {
return itemList;
}
}
5. Retrofit 인터페이스 정의
API 엔드포인트에 대한 호출을 정의하는 Retrofit 인터페이스를 작성한다.
이 과정에서 @GET, @POST 등의 어노테이션으로 HTTP 요청 메소드를 정의한다.
또한 응답을 Call<T> 객체로 래핑하여 비동기 또는 동기 호출 지원을 결정한다.
// Api_News.java
import retrofit2.Call;
import retrofit2.http.GET;
// NewsApiService.java
public interface Api_News {
@GET("jabistar/data/main/data.json")
Call<Api_Response> getNews();
// getNews() 메소드는 실제 네트워크 호출을 추상화하고,
// Api_Response 타입의 응답을 비동기적으로 반환할 Call 객체를 생성합니다.
}
6. Retrofit 인스턴스 생성
HTTP 클라이언트를 설정하고 인스턴스를 생성한다.
Retrofit.Builder를 사용하여 인스턴스를 생성하고, baseUrl / addConverterFactory 등을 통해 기본 URL 및 JSON 변환을 위한 컨버터를 설정한다.
// Api_Retrofit_Client.java
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class Api_Retrofit_Client {
//Retrofit 인스턴스를 생성하고, 위에서 정의한 서비스 인터페이스를 초기화합니다.
// 이 과정에서 기본 URL과 데이터 컨버터(Gson)를 설정합니다.
private static final String BASE_URL = "https://raw.githubusercontent.com/";
private static Retrofit retrofit = null;
public static Retrofit getClient(){
if(retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
//Retrofit 인스턴스를 싱글턴 패턴으로 생성합니다.
// 이 인스턴스는 네트워크 요청을 보내는 데 사용되며
// baseUrl과 GsonConverterFactory를 설정하여 JSON 데이터를 자동으로 Java 객체로 변환할 수 있도록 합니다.
7. API 호출 및 응답 처리
// Api_Manager.java
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class Api_Manager {
// loadNewsData : Api_News 인터페이스의 구현체 생성
public void loadNewsData(NewsDataListener listener){
Api_News api = Api_Retrofit_Client.getClient().create(Api_News.class);
// enqueue 메소드를 사용하면 네트워크 응답을 비동기적으로 처리
// 동기 방식 : execute()
// 이후 응답 데이터를 UI 컴포넌트에 바인딩
api.getNews().enqueue(new Callback<Api_Response>() {
@Override
public void onResponse(Call<Api_Response> call, Response<Api_Response> response) {
// 데이터 로드 성공 시 onResponse 콜백에서 응답 본문을 파싱하여 Api_Respose 객체로 변환하고
// 이를 통해 뉴스 항목 리스트를 가져와 NewsDataLisnter를 통해 전달
if (response.isSuccessful()){
List<Api_NewsItem> items = response.body().getItemList();
listener.onDataLoaded(items);
}else{
listener.onError(response.errorBody().toString());
}
}
@Override
public void onFailure(Call<Api_Response> call, Throwable t) { // 여기도 NewsResponse로 수정
listener.onError(t.getMessage());
}
});
}
// 콜백 메커니즘 구현 해야함
public interface NewsDataListener {
void onDataLoaded(List<Api_NewsItem> newsItems);
void onError(String errorMessage);
}
}
8. UI 업데이트
네트워크 응답을 받아 UI 컴포넌트, RecyclerView에 표시
// MainActivity.java
// NewsApi 데이터 로드 메소드 호출
Api_Manager newsApiManager = new Api_Manager();
newsApiManager.loadNewsData(new Api_Manager.NewsDataListener() {
@Override
public void onDataLoaded(List<Api_NewsItem> newsItems) {
// 데이터 로드 성공 시 어댑터에 데이터 설정
// onDataLoaded 콜백 내부 또는 어댑터를 설정하는 곳에서
NewsRvAdapter_NewsFlash newsFlashAdapter = new NewsRvAdapter_NewsFlash(getContext(), new ArrayList<>(newsItems), Fragment_01_General.this);
binding.rvNewsflash.setAdapter(newsFlashAdapter);
binding.rvRank.setAdapter(new NewsRvAdapter_Rank(getContext(), new ArrayList<>(newsItems)));
}
@Override
public void onError(String errorMessage) {
// 데이터 로드 실패 처리
String message = getContext().getString(R.string.data_load_fail) + errorMessage;
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
Log.d(getContext().getString(R.string.Fragment_01_General), errorMessage);
}
});
<결과>
공식문서 ▼
https://devflow.github.io/retrofit-kr/
Retrofit - 한글 문서
A type-safe HTTP client for Android and Java
devflow.github.io
'Android' 카테고리의 다른 글
[Android] RecyclerView를 update하는 메소드 (0) | 2024.02.28 |
---|---|
[Android] RecyclerView - GridLayout 구현하기 (1) | 2024.02.27 |
[Android] Glide를 사용해서 네트워크 이미지 로드하기 (0) | 2024.02.21 |
[Android] RecyclerView 스크롤 차단하기 (0) | 2024.02.20 |
[Android] RecyclerView (2) - CardView를 활용해서 구현해보기 (0) | 2024.02.15 |