使Forecast list可点击

    Domain model和数据映射时必须生成完整的图标uil,所以我们可以这样去加载它:

    1. data class Forecast(val date: String, val description: String,
    2. val high: Int, val low: Int, val iconUrl: String)

    ForecastDataMapper中:

    1. private fun convertForecastItemToDomain(forecast: Forecast): ModelForecast {
    2. return ModelForecast(convertDate(forecast.dt),
    3. forecast.weather[0].description, forecast.temp.max.toInt(),
    4. forecast.temp.min.toInt(), generateIconUrl(forecast.weather[0].icon))
    5. }
    6. private fun generateIconUrl(iconCode: String): String
    7. = "http://openweathermap.org/img/w/$iconCode.png"

    我们从第一个请求中得到图标的code,用来组成完成的图标url。加载图片最简单的方式是使用图片加载库。是一个不错的选择。它需要加到build.gradle的依赖中:

    1. }

    如果你还记得上一课程,当被调用时invoke方法可以被省略。所以我们来使用它来简化。listener可以被以下两种方式调用:

    1. itemClick.invoke(forecast)
    2. itemClick(forecast)

    ViewHolder将负责去绑定数据到新的View:

    现在Adapter的构造方法接收一个itemClick。创建和绑定数据也是更简单:

    1. public class ForecastListAdapter(val weekForecast: ForecastList,
    2. val itemClick: ForecastListAdapter.OnItemClickListener) :
    3. RecyclerView.Adapter<ForecastListAdapter.ViewHolder>() {
    4. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
    5. ViewHolder {
    6. .inflate(R.layout.item_forecast, parent, false)
    7. }
    8. override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    9. holder.bindForecast(weekForecast[position])
    10. }
    11. ...
    12. }
    1. val View.ctx: Context

    从现在开始,任何View都可以使用这个属性了。这个不是必须的,因为你可以使用扩展的context属性,但是我觉得如果我们使用的话在其它类中也会更有连贯性。而且,这是一个很好的怎么去使用扩展属性的例子。

    最后,MainActivity调用setAdapter,最后结果是这样的:

    如你所见,创建一个匿名内部类,我们去创建了一个实现了刚刚创建的接口的对象。看起来不是很好,对吧?这是因为我们还没开始试使用另一个强大的函数式编程的特性,但是你将会在下一章中学习到怎么去把这些代码转换得更简单。