怠慢プログラマーの備忘録

怠慢でナマケモノなプログラマーの備忘録です。

【kotlin】Retrofit2+SimpleXMLConverterでRSSを取得する

以前会社でリリースさせてもらったiOSアプリのAndroidアプリを作成しています。

新潟永住計画

新潟永住計画

  • CUNEL WORK CO., LTD.
  • ニュース
  • 無料

iOSではXMLParserを使用していましたが、AndroidでやるならせっかくなのでRetrofitで実装したいと思い今回実装しました。

まず取得したいRSSは以下の通りです。

<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
    xmlns="http://purl.org/rss/1.0/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:admin="http://webns.net/mvcb/"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" 
>
    <channel rdf:about="https://ng-life.jp">
        <title>新潟永住計画</title>
        <link>https://ng-life.jp</link>
        <description>新時代の直感型ローカルWEBマガジン</description>
        <dc:date>2018-03-23T03:00:55Z</dc:date>
        <sy:updatePeriod>hourly</sy:updatePeriod>
        <sy:updateFrequency>1</sy:updateFrequency>
        <sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
        <admin:generatorAgent rdf:resource="https://wordpress.org/?v=4.9.4" />
        <atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/>
        <atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/>
        <items>
            <rdf:Seq>
                <rdf:li rdf:resource="https://ng-life.jp/food/20330/"/>
            </rdf:Seq>
        </items>
    </channel>
    <item rdf:about="https://ng-life.jp/food/20330/">
        <title>にいがた酒の陣2018に行ってきた!日本酒は人と人とを繋ぐ宝物!!</title>
        <link>https://ng-life.jp/food/20330/</link>
        <dc:date>2018-03-23T03:00:55Z</dc:date>
        <dc:creator>
            <![CDATA[]]>
        </dc:creator>
        <description>
            <![CDATA[<div><img width="660" height="495" src="https://ng-life.jp/mag/wp-content/uploads/2018/03/DSCN0655.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" /></div>]]>
        </description>
        <content:encoded>
        <![CDATA[<h2>今年も記録更新!14万人以上が来場した酒の陣2018</h2>
         </content:encoded>
</item>
<item rdf:about="https://ng-life.jp/food/20054/">
    <title>引越しのご挨拶におススメの新潟ギフトまとめ!ちょっとした贈り物にピッタリ!</title>
    <link>https://ng-life.jp/food/20054/</link>
    <dc:date>2018-03-19T03:02:47Z</dc:date>
    <dc:creator>
        <![CDATA[]]>
    </dc:creator>
    <description>
        <![CDATA[<div><img width="380" height="320" src="https://ng-life.jp/mag/wp-content/uploads/2018/02/shigenonousan_0113_001_20-380x320.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" /></div>]]>
    </description>
    <content:encoded>
    <![CDATA[<h2>出会いと別れの季節に頭を悩ますご挨拶</h2>]]>
    </content:encoded>
</item>
<item rdf:about="https://ng-life.jp/food/20169/">
    <title>沼垂(ぬったり)の大人気イベント“発酵・大醸し祭り2018春”が4月14~15日に開催決定!</title>
    <link>https://ng-life.jp/food/20169/</link>
    <dc:date>2018-03-18T03:01:04Z</dc:date>
    <dc:creator>
        <![CDATA[]]>
    </dc:creator>
    <description>
        <![CDATA[<div><img width="660" height="495" src="https://ng-life.jp/mag/wp-content/uploads/2018/02/IMG_3375-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" /></div>]]>
     </description>
     <content:encoded>
     <![CDATA[<h2>発酵のまち沼垂地区</h2>
     </content:encoded>
</item>
....

build.gradleにライブラリ追加

build.gradle

dependencies {
...

    compile 'com.squareup.retrofit2:retrofit:2.4.0'
    compile "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
    compile 'com.squareup.retrofit2:converter-simplexml:2.3.0'
    compile 'io.reactivex.rxjava2:rxkotlin:2.0.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'
}

Retrofitのインターフェースを定義

Client.kt

import io.reactivex.Observable
import retrofit2.http.GET

/**
 * Retrofit用のクライアント
 */

interface EijuClient {
    @GET("/feed/rdf/")
    fun get() : Observable<Article>
}

Retrofit実装&ResponseをSubscribe

Activity or Fragment or Repository.kt

import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.simplexml.SimpleXmlConverterFactory

...

private fun loadXml() {
        val retrofit = Retrofit.Builder()
                .baseUrl("https://ng-life.jp/")
                .addConverterFactory(SimpleXmlConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()

        val response = retrofit.create(EijuClient::class.java).get()

        response.subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ entities ->
                    println("succese")
                }, { error ->
                    println("error")
                })
    }

Entityを追加

個人的にEntityを作成するときのアノテーション周りが一番苦労しました。 もう、ひたすらこれを読むしかない。↓

simple.sourceforge.net

ArticleEntity.kt

import org.simpleframework.xml.*

@Root(strict = false)
class Article {
    @set:ElementList(entry = "item", inline = true)
    @get:ElementList(entry = "item", inline = true)
    var articleEntities: List<ArticleEntity>? = null
}

@Root(name = "item", strict = false)
class ArticleEntity {

    @set:Element(name = "title")
    @get:Element(name = "title")
    var title: String? = null

    @set:Element(name = "link")
    @get:Element(name = "link")
    var link: String? = null

    @set:Element(name = "date")
    @get:Element(name = "date")
    var date: String? = null

    @set:Element(name = "creator", required = false)
    @get:Element(name = "creator", required = false)
    var creator: String? = null

    @set:Element(name = "description", required = false)
    @get:Element(name = "description", required = false)
    var description: String? = null
}

最終的に上記の例だと、下記の画像のようにデバッグで確認できました。 f:id:ka0in:20180324000456p:plain

Androidアプリ開発のためのKotlin実践プログラミング

Androidアプリ開発のためのKotlin実践プログラミング

Kotlinイン・アクション

Kotlinイン・アクション

Kotlinスタートブック

Kotlinスタートブック