1. Retrofit
1-1. Retrofit 이란?
1-2. TMI
2. 기본 개념
2-1. Request URL
2-2. JSON과 HTML
2-3. GET과 POST
2-4. parameter
3. 사용 전 세팅
3-1. gradle
3-2. AndroidManifest.xml
3-3. data class 생성
1. Retrofit
1-1. Retrofit 이란?
Retrofit는 서버와 클라이언트 간 http 통신을 위한 라이브러리이다.
더 쉽게 말하자면 안드로이드에서 http 통신을 할 수 있도록 도와주는 놈이다.
예를 들어, retrofit 라이브러리를 사용하면 위 사이트의 공지사항들을 불러올 수 있다.
이를 이용하면 최저가 상품을 모아서 보여준다던가, 쇼핑몰 옷 사진들을 모아서 보여준다던가 등의 구현이 가능한 것이다.
사이트의 정보를 무작정 가져오는 것은 윤리적으로 금지된 행위이다.
자세한 내용은 이 게시물의 [목차 6]에서 다루었다.
배달의 민족 사이트는 허용하고 있어 예제로 사용했다.
1-2. TMI
예전에도 통신을 편하게 할 수 있도록 도와주는 라이브러리가 있었다.
HttpClient, Volley, OKhttp... 하지만 앞서 말한 2개는 Deprecated 되어 역사 속으로 사라졌고, OKhttp를 이용해서 더 편하고 사용하기 쉽게 만든 것이 Retrofit이다. 그래서 요즘은 전부 Retrofit을 사용하는 추세인 것 같다.
OKhttp를 기반으로 Retrofit을 만들었기 때문에 Retrofit 라이브러리를 추가하면 OKhttp의 메서드도 사용할 수 있다.
2. 기본 개념
- 어떤 주소로 요청을 보내야 하는가?
- 어떤 형태로 응답을 받는가?
- 어떤 형태로 요청을 해야 하는가?
- 어떤 파라미터를 가지고 요청해야 하는가?
Retrofit을 사용하기 전에 알아두어야 할 개념들이 있다. 만약 위 항목에 대해 답할 수 있다면 [목차 3]으로 넘어가면 된다. 아니라면 [목차 2]를 계속 읽어 나가면 된다.
2-1. Request URL
통신할 사이트에 들어가서 F12를 누르면 위와 같은 창이 뜬다.
해당 경로로 들어가 Ctrl + R을 눌러주자.
그러면 이렇게 알 수 없는 파일들이 쪼라ㅏ라라락 생기는데 이 파일들이 화면을 구성한다고 생각하면 될 것 같다.
이 중 우리가 필요한 파일을 찾아내야 하는데 공지사항처럼 1페이지, 2페이지가 있는 페이지라면 비교적 찾기가 쉽다.
개발자 도구 창을 그대로 둔 상태에서 2페이지로 넘어가 보자.
사이트에 접속 후 몇 초정도 있다가 2페이지로 넘어갔더니 이전 작업 내용들은 저렇게 작아지고 새로운 작업 내용이 생겼다. 저 파란색 부분을 클릭해보자. (드래그하면 넓게 선택됨)
그러면 이렇게 저 시간 때에 바뀐 내용들을 볼 수 있다. 1페이지 -> 2페이지로 넘어갔다면 아마 사이트의 다른 부분들 예를 들어 로고나... 카테고리 이름이라던가... 로그인 버튼 등은 바뀔 필요가 없으니 변경사항이 없을 거고 게시물 목록이 바뀌었을 테니 저 목록 중 게시물 목록을 담당하는 놈을 찾아주면 된다.
항목을 클릭하고 Preview 탭에 들어가면 내용을 확인할 수 있다.
내용을 보아하니 이놈이 내가 찾던 놈이구만?
Header에 들어가면 그렇게 찾아 헤매던 Request URL을 알아낼 수 있다.
안드로이드에서 HTTP 통신을 할 때 우리가 흔히 사용하는 url 주소를 사용하는 게 아니라 이걸 사용해야 한다.
크롬 주소창에 있는 그 주소는 사용하기 편하라고 간편하게 줄여놓은 거고 이게 진짜 request를 하기 위한 주소이다.
1-2. JSON과 HTML
request를 했을 때 사이트에서 응답해주는 값이 json형태 일수도 있고 html형태일 수도 있다.
앞서 보여주었던 배달의 민족 사이트가 json 그리고 지금 위에 보이는 사진이 html 형태이다.
(딱 봐도 느낌 오시쥬? 😉)
차이점을 설명하기엔 오늘 게시물이 너무 길어질 것 같으므로 내가 요청을 보내고자 하는 사이트가 어떤 형태로 응답을 하는지 알아두기만 하고 넘어가자. 형태에 따라 뒤에서 해야 할 것이 달라지므로...
1-3. GET과 POST
앞서 말했듯이 응답을 받는 형태도 여러 종류가 있지만 보내는 요청의 형태도 여러 가지가 있다.
GET, POST, PUT, DELETE 총 4가지가 있으나 이 게시물에서는 크롤링을 목적으로 Retrofit을 사용할 것이기 때문에 GET과 POST만 확인하면 된다.
만약 Request Method가
GET으로 되어있다면 우리는 GET 요청을 해야만 응답을 받을 수 있고
POST로 되어있다면 POST 요청을 해야만 응답을 받을 수 있다.
즉 사이트에서 정해놓은 방법대로 요청을 해야 한다는 것이다.
보통은 GET 요청으로 게시물을 조회할 수 있도록 만들어두는 것이 권장되는 방법이지만
POST를 이용하도록 만든 사이트들도 있다. (우리 학교 사이트가 이랬음...)
GET과 POST에 대한 자세한 내용은 따로 글을 올려야 할 것 같다.
1-4. parameter
파라미터 없이 요청만 하면 결과를 내놓는 사이트도 있고
파라미터가 있어야 결과를 내놓는 사이트도 있다.
일단, 파라미터 목록은 Header 탭에 같이 적혀있다. 단 저기에 있는 게 전부 필요한 건 아니고 필수 파라미터를 골라내야 한다. 예를 들어 몇 페이지를 요청할 건지는 꼭 알려줘야 하기 때문에 page는 필수 파라미터인 걸 알 수 있다. 문제는 이렇게 때려 맞춰서 어떤 게 필수 파라미터인지 찾아내는 건 불확실하다는 거 (필수 여부는 정하는 사람 마음이라.. 😔)
이때 postman을 이용하면 편하다. api를 테스트하는 프로그램이다. request URL을 붙여 넣고 parameter를 하나씩 빼보면서 요청을 보내보면 응답 결과로 필수 파라미터를 구분할 수 있다.
파라미터를 뺐는데 결과가 잘 나온다? -> 필수 파라미터 아님
파라미터를 뺐는데 결과가 안 나온다? -> 필수 파라미터
아무튼 이렇게 꼭 필요한 기본 개념이 끝났다. 드럽게 기네... 읽다가 도망가시면 안 돼요 저 힘들게 썼어요 ㅠㅠ
2. 사용 전
2-1. gradle 추가
최신 버전은 Retrofit GitHub에서 확인할 수 있다.
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
retrofit을 사용하려면 gradle을 추가해야 한다.
두 번째 줄에 있는 converter-gson은 응답 결과가 JSON일 때 객체로 변환해주는 놈이다.
2-2. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="_">
<uses-permission android:name="android.permission.INTERNET"/> <--------- 1번
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SelfStudy_Kotlin"
android:usesCleartextTraffic="true"> <----------- 2번
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
1번은 서버와 통신을 하기 위해 인터넷 권한을 얻는 거고
2번은 http로 시작하는 사이트에 접근하기 위해서 적어준다.
(안드로이드는 기본적으로 http 접근을 허용하지 않기 때문. 만약 https를 지원하는 사이트와 통신할 거면 안 적어줘도 된다)
2-3. data class 생성
사이트에서 받아온 값이 JSON이라면 그에 맞게 데이터 타입을 준비해두어야 한다.
일단 위 결과를 정리해보면 아래처럼 표현할 수 있다.
응답 결과
└ timestamp
└ statusCode
└ statusMessage
└ data
└ content[0] // '{'가 아닌 '['로 시작했다는 건 배열이란 뜻이다.
└ contentId
└ contentSeq
└ title
└ content
.
.
.
이걸 date class로 바꾸면 아래처럼 표현할 수 있다.
data class Baemin(val timestamp: Long, val statusCode: String, val statusMessage: String, val data: Data)
data class Data(val content: ArrayList<Content>)
data class Content(val contentId: Long, val contentSeq: Long, val title: String, val created: String)
Baemin은 임의로 정해준 이름이고, 나머지는 JSON에 정해져 있는 그대로 사용한 것이다.
content는 배열이기 때문에 ArrayList로 선언하였다.
data class Baemin(val data: Data)
data class Data(val content: ArrayList<Content>)
data class Content(val title: String, val created: String)
나는 title과 created만 필요하다! 나는 쓸데없이 다른 데이터까지 다 가져오고 싶지 않다! 하면 위와 같이 필요 없는 건 지워버리면 된다.
data class Baemin(val data: Data)
data class Data(val content: ArrayList<Content>)
data class Content(
@SerializedName("title")
val title: String,
@SerializedName("created")
val date: String
)
JSON에 정해져 있는 이름을 사용하다 보면 마음에 안 드는 변수명이 있을 수도 있다.
예를 들어 created라는 변수명 대신에 date를 사용하고 싶다 하면
위에 @SerializedName("")을 붙여 원래 변수명을 넣어주고 그 밑에 변수를 선언할 때는 원하는 변수명을 사용하면 된다.
@SerializedName은 Gson 라이브러리에서 제공하는 어노테이션인데
여기서 Serialize는 data class 객체를 JSON 형태로 변환하는 것을 말한다.
한국말로는 직렬화인데 영어나 한국말이나 드럽게 어렵네 😑
아무튼 그래서 @SerializedName을 이용하면 'date'의 직렬화된 이름은 'created'입니다.라는 뜻이 되는 것이다.
이렇게 표시해두면 GSON converter가 JSON을 받아와서 어노테이션을 보고 'created'값을 'date'에 매핑해준다.
분량 조절 실패로 Retrofit 사용 방법은 다음 게시물에서...
💡 느낀 점
- 이 블로그를 처음 개설했을 때 Retrofit에 대해 게시글을 쓴 적이 있었다. 그땐 정리하면서도 감이 잘 안 왔는데 역시 실제로 사용해봐야 확실히 알게 되는 것 같다.
- 예전에는 JSON 대신에 XML 형태를 많이 썼다는 듯하다.
- JSON으로 통일해서 리턴해주면 편할 것 같은데 HTML로 리턴하는 사이트도 있어서 불편하다. HTML은 파싱 작업도 거쳐야 해서 비교적 코드가 더러워지고 시간도 더 걸리는 것 같아서 영... 어쩔 수 없는 웹 세상만의 사정이 있겠지? (나는야 웹알못)
📘 참고한 자료
'오늘은 뭘 배울까? > Android' 카테고리의 다른 글
안드로이드 Jetpack이란? (3) | 2021.04.05 |
---|---|
안드로이드 Room의 사용법과 예제 (18) | 2021.04.03 |
Retrofit으로 html response 얻기 (webView 사용 아님) (2) | 2021.03.16 |
앱을 삭제했는데 데이터가 남아있어요 + Room cannot verify the data integrity. (0) | 2021.03.13 |
RecyclerView + MVVM + Room을 연습해보자! (0) | 2021.03.11 |
댓글