Now we will create the producer. To do so, let's first create a package co.starcarr.rssreader.producer and put the file ArticleProducer.kt inside it:
In that file, we will create an object ArticleProducer and we will move some of the code from the activity there, starting with the list of feeds:
object ArticleProducer {
private val feeds = listOf(
Feed("npr", "https://www.npr.org/rss/rss.php?id=1001"),
Feed("cnn", "http://rss.cnn.com/rss/cnn_topstories.rss"),
Feed("fox", "http://feeds.foxnews.com/foxnews/latest?format=xml")
)
}
We will also move the dispatcher and the factory here:
object ArticleProducer {
...
private val dispatcher = newFixedThreadPoolContext(2, "IO")
private val factory = DocumentBuilderFactory.newInstance()
}
Finally, we will move the function asyncFetchArticles(). Now, it will be called fetchArticles() and will return a List<Article> directly:
object ArticleProducer {
...
private fun fetchArticles(feed: Feed) : List<Article> {
...
}
}
In order for this function to compile, we will have to add a return statement at the end of it. Something simple like the following will work:
private fun fetchArticles(feed: Feed) : List<Article> {
val builder = factory.newDocumentBuilder()
val xml = builder.parse(feed.url)
val news = xml.getElementsByTagName("channel").item(0)
return (0 until news.childNodes.length)
.map { news.childNodes.item(it) }
.filter { Node.ELEMENT_NODE == it.nodeType }
.map { it as Element }
...
}
So we are only missing the actual producer. Since we want to fetch each feed on demand, we only need to iterate through the list of feeds, sending the articles of each feed. A simple implementation would be the following:
val producer = produce(dispatcher) {
feeds.forEach {
send(fetchArticles(it))
}
}
Notice that now we are sending all the articles of each feed through the producer. So this is a Producer<List<Article>>.