I'm learning the sample code about Anko at Kotlin for Android Developers (the book) https://github.com/antoniolg/Kotlin-for-Android-Developers
The Method 1 is from sample code and override parseList ,but it's hard to understand.
So I try to use the Method 2 instead of the Method 1, the Method 2 use original parseList function, but I get blank record when I use the Method 2, what error do I made in the Method 2
class DayForecast(var map: MutableMap<String, Any?>) {
var _id: Long by map
var date: Long by map
var description: String by map
var high: Int by map
var low: Int by map
var iconUrl: String by map
var cityId: Long by map
constructor(date: Long, description: String, high: Int, low: Int,
iconUrl: String, cityId: Long) : this(HashMap()) {
this.date = date
this.description = description
this.high = high
this.low = low
this.iconUrl = iconUrl
this.cityId = cityId
}
}
Method 1
override fun requestForecastByZipCode(zipCode: Long, date: Long) =
forecastDbHelper.use {
val dailyRequest = "${DayForecastTable.CITY_ID} = ? AND ${DayForecastTable.DATE} >= ?"
val dailyForecast = select(DayForecastTable.NAME)
.whereSimple(dailyRequest, zipCode.toString(), date.toString())
.parseList { DayForecast(HashMap(it)) }
/* common code block */
}
fun <T : Any> SelectQueryBuilder.parseList(parser: (Map<String, Any?>) -> T):
List<T> = parseList(object : MapRowParser<T> {
override fun parseRow(columns: Map<String, Any?>): T = parser(columns)
})
Method 2
override fun requestForecastByZipCode(zipCode: Long, date: Long) =
forecastDbHelper.use {
val dailyRequest = "${DayForecastTable.CITY_ID} = ? AND ${DayForecastTable.DATE} >= ?"
val dailyForecast = select(DayForecastTable.NAME)
.whereSimple(dailyRequest, zipCode.toString(), date.toString())
.exec { parseList(classParser<DayForecast>()) }
/* common code block */
}
I really do think you should stick to using the 'method 1' approach, it's a lot easier once you realise what Kotlin is letting you do. As I don't know how much you know about Kotlin, I'll try to cover this completely.
The existing class SelectQueryBuilder
has (I presume) a function called parseList
, that existing function takes a MapRowParser<T>
. The MapRowParser<T>
has a function parseRow
that takes a Map<String, Any?>
and returns a T
.
In the old Java way of working, you would derive from MapRowParser<T>
and would override parseRow
so that it does the conversion you want; converting the Map<String, Any?>
into a DayForecast
(the generic T
would now have a type). An instance of this derived class is passed into the existing parseList
function. Your derived class would look something like
class MapToDayForecastRowParser extends MapRowParser<DayForecast> {
@Override public DayForecast parseRow(Map<String, Object> map) {
// Note that Java's "Object" is more or less Kotlin's "Any?"
return new DayForecast(map); // Might need to convert the map type btw
}
}
The extension method is making it really easy to wrap/hide/abstract that creation of the derived class. The extension method take a lambda, that is, you have to parse into the new parseList
method a block of code that takes a Map<String, Any?>
and returns T
(this is what DayForecast(HashMap(it))
is doing, the it
is an automatically named variable that is the Map
. The extension method then calls the existing parseList
method, parsing in an anonymous class that it creates itself. That means that ever use of this extension method creates a new anonymous class, but the Kotlin compiler handles this very well.
One part that did confuse me at first is the way Kotlin handles the anonymous class.
// Java
new MapRowParser<T>() {
@Override public T parseRow(Map<String, Object>) {
/* Map to T logic */
}
}
// Kotlin
object : MapRowParser<T> {
override fun parseRow(columns: Map<String, Any?>): T = parser(columns)
}
Kotlin also makes it very easy to handle the 'lambda'. It is parsed into the extension method as parser
and then set as the implementation of our anonymous class parseRow
function. You can also reuse them if you so wished, your so if you need to do the same sort of parsing in lots of places, you can use a named function instead.
The great advantage to this new Kotlin way is that it's very easy focus on what you want to do. With that extension method in place, it's very quick to re-use it so that in another query you can do parseList{ it.getOrDefault("name", "unkown_user") }
. You can now easily work on just thinking "If each row is a map, how do I convert that down to a value I want?".
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句