Github : https://github.com/junghun9102/AndroidTemplate
Branch : library/retrofit
Commit ea187676
기본 사용법
1. Service
2. OkHttpClient
3. Retrofit을 이용한 Service 구현체
1번과 3번만 구현하면 API통신이 가능하다.
2번은 선택적이지만 보통 구현한다.
GoogleNews RSS를 사용해 Retrofit 기본 사용법을 정리하려고 한다.
https://news.google.com/rss?hl=ko&gl=KR&ceid=KR:ko
https://square.github.io/retrofit/
dependencies
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.squareup.retrofit2:converter-simplexml:2.1.0'
// implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
1. Service
HTTP Method(GET/POST/PUT/DELETE)로 API 요청을 위한 interface
interface GoogleNewsService {
@GET("/rss")
fun getNews(
@Query("hl") hl: String,
@Query("gl") gl: String,
@Query("ceid") ceid: String
): Call<RespNewsRss>
}
추가적인 사용 방법들은 아래 포스팅에 잘 설명되어 있다.
2. OkHttpClient
API 요청과 응답에 관한 설정을 할 수 있다.
object GoogleNewsServiceFactory
private const val HTTP_TIMEOUT_READ = 10L
private const val HTTP_TIMEOUT_CONNECT = 5L
private fun makeOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor, appendHeaderInterceptor: Interceptor) = OkHttpClient.Builder()
.connectTimeout(HTTP_TIMEOUT_CONNECT, TimeUnit.MILLISECONDS)
.readTimeout(HTTP_TIMEOUT_READ, TimeUnit.MILLISECONDS)
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(appendHeaderInterceptor)
.build()
private fun makeLoggingInterceptor(debug: Boolean): HttpLoggingInterceptor {
return HttpLoggingInterceptor().apply {
level = if (debug) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
}
}
private fun makeAppendHeaderInterceptor() = Interceptor { chain ->
val newRequest = chain.request().newBuilder()
// newRequest.addHeader("Version", "v1.0")
chain.proceed(newRequest.build())
}
connectTimeout / readTimeout / writeTimeout / callTimeout
타임아웃을 설정 가능
HttpLoggingInterceptor
요청과 응답 로그를 볼 수 있다.
makeAppendHeaderInterceptor
1번의 Service에서도 각각의 요청마다 Header를 붙일 수 있다.
하지만 디폴트 헤더 데이터가 필요한 경우 interceptor를 만들어 요청마다 같은 헤더를 추가할 수 있다.
3. Retrofit을 이용한 Service 구현체
실제 사용하기 위한 구현체 생성
object GoogleNewsServiceFactory
fun makeNewsService(debug: Boolean, baseUrl: String): GoogleNewsService {
val okHttpClient = makeOkHttpClient(
makeLoggingInterceptor(debug),
makeAppendHeaderInterceptor()
)
return makeNewsService(
baseUrl,
okHttpClient
)
}
private fun makeNewsService(baseUrl: String, okHttpClient: OkHttpClient): GoogleNewsService {
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build()
return retrofit.create(GoogleNewsService::class.java)
baseUrl(baseUrl)
기본 URL을 설정
client(okHttpClient)
2번에서 만들었던 okHttpClient 설정
addConverterFactory(SimpleXmlConverterFactory.create())
응답 데이터를 파싱해 객체로 받기 위한 설정
XML
dependecies
implementation 'com.squareup.retrofit2:converter-simplexml:2.1.0'
Retrofit Builder
addConverterFactory(SimpleXmlConverterFactory.create())
<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<generator>NFE/5.0</generator>
<title>주요 뉴스 - Google 뉴스</title>
<link>https://news.google.com/?hl=ko&gl=KR&ceid=KR:ko</link>
<language>ko</language>
<webMaster>news-webmaster@google.com</webMaster>
<copyright>2020 Google Inc.</copyright>
<lastBuildDate>Fri, 29 May 2020 03:09:37 GMT</lastBuildDate>
<description>Google 뉴스</description>
<item>
<title>[속보] 코로나19 확진 58명 늘어…신규 확진자 전원 수도권 - 한겨레</title>
<link>https://news.google.com/__i/rss/rd/articles/CBMiNWh0dHA6Ly93d3cuaGFuaS5jby5rci9hcnRpL3NvY2lldHkvaGVhbHRoLzk0NzA1Ny5odG1s0gEA?oc=5</link>
<guid isPermaLink="false">52782408608000</guid>
<pubDate>Fri, 29 May 2020 01:23:03 GMT</pubDate>
<description><ol><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiNWh0dHA6Ly93d3cuaGFuaS5jby5rci9hcnRpL3NvY2lldHkvaGVhbHRoLzk0NzA1Ny5odG1s0gEA?oc=5" target="_blank">[속보] 코로나19 확진 58명 늘어…신규 확진자 전원 수도권</a> <font color="#6f6f6f">한겨레</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9UEFEOE1UVXBoMmfSAQA?oc=5" target="_blank">쿠팡발 감염 확산에 수도권 '비상'…모자·신발서 코로나 나와</a> <font color="#6f6f6f">뉴스TVCHOSUN</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiMWh0dHBzOi8vd3d3Lnl0bi5jby5rci9fbG4vMDEwM18yMDIwMDUyOTEwNTI0NDc0NDbSAUNodHRwczovL20ueXRuLmNvLmtyL25ld3Nfdmlldy5hbXAucGhwP3BhcmFtPTAxMDNfMjAyMDA1MjkxMDUyNDQ3NDQ2?oc=5" target="_blank">신규 발생 58명...지역 발생 55명 모두 수도권에 집중</a> <font color="#6f6f6f">YTN</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiJ2h0dHBzOi8vbmV3cy5qb2lucy5jb20vYXJ0aWNsZS8yMzc4ODg4MNIBK2h0dHBzOi8vbW5ld3Muam9pbnMuY29tL2FtcGFydGljbGUvMjM3ODg4ODA?oc=5" target="_blank">코로나 신규환자 58명, 지역감염 55명···모두 수도권서 터졌다 - 중앙일보</a> <font color="#6f6f6f">중앙일보 모바일</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9cnVjU2VzMVB0R2_SAQA?oc=5" target="_blank">수도권 덮친 '쿠팡 물류센터 집단감염'…"2주가 고비" / JTBC 뉴스룸</a> <font color="#6f6f6f">JTBC News</font></li><li><strong><a href="https://news.google.com/stories/CAAqOQgKIjNDQklTSURvSmMzUnZjbmt0TXpZd1NoTUtFUWlBMHR6bGxZQU1FVmdIQWUwRXpZRzRLQUFQAQ?oc=5" target="_blank">Google 뉴스에서 전체 콘텐츠 보기</a></strong></li></ol></description>
<source url="http://www.hani.co.kr">한겨레</source>
</item>
@Root(name = "rss", strict = false)
data class RespNewsRss(
@field:Element(name = "channel") var channel: RespNewsRssChannel? = null
)
@Root(name = "channel", strict = false)
class RespNewsRssChannel(
@field:ElementList(entry = "item", inline = true) var newsList: List<RespNews>? = null
)
@Element(name = "item")
data class RespNews(
@field:Element(name = "title") var title: String? = null,
@field:Element(name = "link") var link: String? = null,
@field:Element(name = "guid") var guid: String? = null,
@field:Element(name = "pubDate") var pubDate: String? = null,
@field:Element(name = "description") var description: String? = null,
@field:Element(name = "source") var source: String? = null
)
Json
depenencies
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
Retrofit Builder
.addConverterFactory(GsonConverterFactory.create())
{
"rss" : {
"channel" : {
"items" : [{
"title" : "인천시 “쿠팡물류센터 확진자 딸 등 2명 추가 확진” - 한겨레",
"link" : "https://news.google.com/__i/rss/rd/articles/CBMiM2h0dHA6Ly93d3cuaGFuaS5jby5rci9hcnRpL2FyZWEvY2FwaXRhbC85NDcyMjIuaHRtbNIBAA?oc=5",
"guid" : "52782408608000",
"pubDate" : "Sun, 31 May 2020 05:56:12 GMT",
"description" : "<ol><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiM2h0dHA6Ly93d3cuaGFuaS5jby5rci9hcnRpL2FyZWEvY2FwaXRhbC85NDcyMjIuaHRtbNIBAA?oc=5" target="_blank">인천시 “쿠팡물류센터 확진자 딸 등 2명 추가 확진”</a> <font color="#6f6f6f">한겨레</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiOGh0dHBzOi8vd3d3Lmhhbmtvb2tpbGJvLmNvbS9OZXdzL1JlYWQvMjAyMDA1MzAxNjc3MDQ3MzMy0gEA?oc=5" target="_blank">이태원 클럽→쿠팡 물류센터→여의도 학원 전파?</a> <font color="#6f6f6f">한국일보</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiNWh0dHA6Ly93d3cuaGFuaS5jby5rci9hcnRpL3NvY2lldHkvaGVhbHRoLzk0NzE4OS5odG1s0gEA?oc=5" target="_blank">부천 쿠팡물류센터 관련 코로나19 확진자 최소 109명</a> <font color="#6f6f6f">한겨레</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiJ2h0dHBzOi8vbmV3cy5qb2lucy5jb20vYXJ0aWNsZS8yMzc4OTYxONIBK2h0dHBzOi8vbW5ld3Muam9pbnMuY29tL2FtcGFydGljbGUvMjM3ODk2MTg?oc=5" target="_blank">쿠팡 물류센터 총 108명 확진…"이태원클럽 학원강사발 추정" - 중앙일보</a> <font color="#6f6f6f">중앙일보 모바일</font></li><li><a href="https://news.google.com/__i/rss/rd/articles/CBMiK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9R1RwQ3ZuQ2I2U1nSAQA?oc=5" target="_blank">코로나19 신규 확진 39명…수도권 이어 지역서도 산발 감염</a> <font color="#6f6f6f">뉴스TVCHOSUN</font></li><li><strong><a href="https://news.google.com/stories/CAAqOQgKIjNDQklTSURvSmMzUnZjbmt0TXpZd1NoTUtFUWlBMHR6bGxZQU1FV1BYSElmd2VCR2RLQUFQAQ?oc=5" target="_blank">Google 뉴스에서 전체 콘텐츠 보기</a></strong></li></ol>",
"soruce" : "한겨레"
}]
}
}
}
data class RespNewsRss(
@field:SerializedName("channel") var channel: RespNewsRssChannel? = null
)
class RespNewsRssChannel(
@field:SerializedName("items") var newsList: List<RespNews>? = null
)
data class RespNews(
@field:SerializedName("title") var title: String? = null,
@field:SerializedName("link") var link: String? = null,
@field:SerializedName("guid") var guid: String? = null,
@field:SerializedName("pubDate") var pubDate: String? = null,
@field:SerializedName("description") var description: String? = null,
@field:SerializedName("source") var source: String? = null
)
실제 사용
MainActivity
private val newsService = GoogleNewsServiceFactory.makeNewsService(BuildConfig.DEBUG, "https://news.google.com")
private fun initViews() {
btn_main.setOnClickListener {
newsService.getNews("ko", "KR", "KR:ko")
.enqueue(object : Callback<RespNewsRss> {
override fun onResponse(
call: Call<RespNewsRss>,
response: Response<RespNewsRss>
) {
tv_main.text = response.body()?.channel?.newsList?.toString()
}
override fun onFailure(call: Call<RespNewsRss>, t: Throwable) {
Toast.makeText(this@MainActivity, t.message, Toast.LENGTH_SHORT).show()
}
})
}
}
Commit ad3ddc26
+Rx
1. Service
2. OkHttpClient
3. Retrofit을 이용한 Service 구현체
dependecies 추가
implementation "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0"
1. Service
interface GoogleNewsService {
@GET("/rss")
fun getNews(
@Query("hl") hl: String,
@Query("gl") gl: String,
@Query("ceid") ceid: String
): Single<RespNewsRss>
}
리턴 타입만 바꼈다.
2. 동일함
3. Retrofit을 이용한 Service 구현체
private fun makeNewsService(baseUrl: String, okHttpClient: OkHttpClient): GoogleNewsService {
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.build()
return retrofit.create(GoogleNewsService::class.java)
}
addCallAdapterFactory(RxJava2CallAdapterFactory.create())
기존의 리턴받던 Call에서 Rx객체로 변경하기 위한 한줄이 추가되었다.
실제사용
private val newsService = GoogleNewsServiceFactory.makeNewsService(BuildConfig.DEBUG, "https://news.google.com")
private val compositeDisposable = CompositeDisposable()
private fun initViews() {
btn_main.setOnClickListener {
newsService.getNews("ko", "KR", "KR:ko")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { resp ->
val newsList = resp.channel?.newsList
tv_main.text = newsList.toString()
}.let {
compositeDisposable.add(it)
}
}
}
'창고' 카테고리의 다른 글
custom_dialog (+custom_toast) (0) | 2020.05.02 |
---|---|
Activity간의 화면 전환 (0) | 2020.03.11 |
internal_storage (0) | 2020.02.26 |
permission (0) | 2020.02.26 |
DP(Device Independence Pixel)? (0) | 2019.06.09 |