Kotlinで書いているアプリで、Retrofit2 + OkHttp3でRSSを取得したときのめも。最初、うまくパースされなくてKotlinの問題なのかRetrofitの書き方の問題なのかコンバータのSimpleの書き方の問題なのかわからなくてちょっとハマってしまいました。
取得する対象は、はてなブックマークのRSSです。
http://b.hatena.ne.jp/Rei19/favorite.rss
準備
app/build.gradle
dependencies {
...
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
compile ('com.squareup.retrofit2:converter-simplexml:2.0.2'){
exclude module: 'stax'
exclude module: 'stax-api'
exclude module: 'xpp3'
}
}
実装
HttpClient
// シングルトンでClientを作っておく
object HttpClient {
val instance = OkHttpClient()
}
HatenaRssXml.kt
// パース用のクラス 1
// strict = falseにしないとXML内の全ての要素をclass内に定義する必要がある
@Root(name = "rdf:RDF", strict = false)
class HatenaRssXml {
// @ElementList(inline = true) これだとダメだった。。。
// @Jvmfieldをつけてもうまくいかなかったので謎
@set:ElementList(inline = true)
@get:ElementList(inline = true)
var list: List<HatenaRssItemXml>? = null
}
HatenaRssXml.kt
// パース用のクラス 2
@Root(name = "item", strict = false)
class HatenaRssItemXml {
@set:Element
@get:Element
var title: String = ""
@set:Element
@get:Element
var link: String = ""
@set:Element(required = false)
@get:Element(required = false)
var description: String = ""
// dc:creatorみたいな : で区切られてる要素はPATHを指定する
@Path("dc/creator")
@set:Element
@get:Element
var creator: String = ""
}
HatenaRssService.kt
interface HatenaRssService {
@GET("{userId}/favorite.rss")
fun favorite(@Path("userId") userId: String, @Query("of") startIndex: Int): Observable<HatenaRssXml>
}
使うときはこんな感じ
val adapter = Retrofit.Builder()
.baseUrl("http://b.hatena.ne.jp")
.client(HttpClient.instance)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create()) // XMLのコンバータを指定
.build()
adapter.create(HatenaRssService::class.java)
.favorite(userId, startIndex)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
// このへんてきとう
)