Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin on Android: map a cursor to a list

In Kotlin, What's the best way to iterate through an Android Cursor object and put the results into a list?

My auto-converted Java:

val list = ArrayList<String>()
while (c.moveToNext()) {
    list.add(getStringFromCursor(c))
}

Is there a more idiomatic way? In particular, can it be done in a single assignment of a read-only list? E.g....

val list = /*mystery*/.map(getStringFromCursor)

... or some other arrangement, where the list is assigned fully-formed.

like image 586
Martin Stone Avatar asked Aug 21 '16 16:08

Martin Stone


2 Answers

You can write your own map() which checks against isClosed() and safely close the Cursor after iterating all over its rows like below:

fun <T> Cursor.map(f: (Cursor) -> T): List<T> {
  val items = mutableListOf<T>()
  use {
    while (!it.isClosed && it.moveToNext()) {
      items += f(it)
    }
  }
  return items.toList()
}

Sample usage:

val contacts = cursor.map { it.toContact() }
like image 56
Thuy Trinh Avatar answered Oct 11 '22 11:10

Thuy Trinh


This is what I went with in the end, using kotlin.sequences.generateSequence...

val list = generateSequence { if (c.moveToNext()) c else null }
        .map { getStringFromCursor(it) }
        .toList()

My first attempt was a little shorter:

val list = (1 .. c.count).map {
    c.moveToNext()
    getStringFromCursor(c)
}

Both versions rely on the cursor initially being positioned before the first record (as a new cursor is). The second would throw if that wasn't the case, while the first would return a shorter list.

like image 38
Martin Stone Avatar answered Oct 11 '22 11:10

Martin Stone