kotlin 编写一个简单的天气预报app(五)增加forcast接口并显示

参考资料

OpenWeatherMap提供了一个/forecast接口,用于获取未来几天的天气预报。你可以使用HTTP GET请求访问该接口,并根据你所在的城市或地理坐标获取相应的天气数据。

以下是一个示例请求的URL和一些常用的参数:

URL: http://api.openweathermap.org/data/2.5/forecast

查询参数:

  • q (必需): 城市名称 (e.g. “London,uk”) 或城市ID (可在OpenWeatherMap网站上获得) 或地理坐标 (使用纬度和经度, e.g. “37.7749,-122.4194”)。
  • appid (必需): 你的OpenWeatherMap API密钥。
    可选参数:
    units: 温度单位 (例如 “metric” 表示摄氏度, “imperial” 表示华氏度)。
    lang: 返回的天气描述语言 (例如 “en” 表示英语)。

从openWeatherMap获取forecast

1.在WeatherService接口中增加请求函数。

getForecastByCityName:此方法与 getWeatherByCityName 方法类似,但它检索预报数据而不是当前天气数据。它还采用城市名称和 API 密钥作为参数,并返回 ForecastResponse 类型的 Call 对象,这是从 API 收到的响应。

interface WeatherService {

    @GET("weather")
    fun getWeatherByCityName(
        @Query("q") cityName : String,
        @Query("appid") apiKey : String
    ) : Call<WeatherResponse>

    @GET("forecast")
    fun getForecastByCityName(
        @Query("q") cityName : String,
        @Query("appid") apiKey : String
    ) : Call<ForecastResponse>
}

2.编译一个新的ForecastResponse 类,用于解析天气预报的 JSON 数据。它具有以下属性:

  • cod:表示响应 JSON 中的 cod 值的字符串变量。
  • message:表示响应 JSON 中的消息值的整数变量。
  • cnt:表示响应 JSON 中的 cnt 值的整数变量。
  • forecastCellList:ForecastCell 对象的ArrayList,表示响应JSON 中的预测单元格列表。
  • forecastCity:ForecastCity 对象,表示响应 JSON 中的城市详细信息。
    这些属性使用 @SerializedName 进行注释,以指定 JSON 中相应的键。提供默认值是为了初始化目的。
package com.example.myweather.openWeatherMap

import com.example.myweather.WeatherResponseClouds
import com.example.myweather.WeatherResponseCoord
import com.example.myweather.WeatherResponseWeather
import com.google.gson.annotations.SerializedName

data class ForecastResponse (
    @SerializedName("cod")
    var cod: String = "",
    @SerializedName("message")
    var message: Int = 0,
    @SerializedName("cnt")
    var cnt : Int = 0,
    @SerializedName("list")
    var forecastCellList : ArrayList<ForecastCell>? = null,
    @SerializedName("city")
    var forecastCity: ForecastCity? = null
)


data class ForecastCell (
    @SerializedName("dt")
    val dt: Long,
    @SerializedName("main")
    val main: ForecastMain,
    @SerializedName("weather")
    val weather: List<WeatherResponseWeather>,
    @SerializedName("clouds")
    val clouds: WeatherResponseClouds,
    @SerializedName("wind")
    val wind: ForecastWind,
    @SerializedName("visibility")
    val visibility: Int = 0,
    @SerializedName("pop")
    val pop: Double = 0.0,
    @SerializedName("rain")
    val rain: ForecastRain,
    @SerializedName("snow")
    val snow: ForecastSnow,
    @SerializedName("sys")
    val sys: ForecastSys,
    @SerializedName("dt_txt")
    val dt_txt: String = ""
)

data class ForecastCity(
    @SerializedName("id")
    val id: Int = 0,
    @SerializedName("name")
    val name: String = "",
    @SerializedName("coord")
    val coord: WeatherResponseCoord,
    @SerializedName("country")
    val country: String ="",
    @SerializedName("population")
    val population:Int = 0,
    @SerializedName("timezone")
    val timezone: Int = 0,
    @SerializedName("sunrise")
    val sunrise: Int = 0,
    @SerializedName("sunset")
    val sunset: Int = 0
)

data class ForecastMain(
    @SerializedName("temp")
    val temperature: Double = 0.0,
    @SerializedName("feels_like")
    val feelsLike: Double = 0.0,
    @SerializedName("temp_min")
    val minTemperature: Double = 0.0,
    @SerializedName("temp_max")
    val maxTemperature: Double = 0.0,
    @SerializedName("pressure")
    val pressure: Int = 0,
    @SerializedName("sea_level")
    val seaLevel: Int = 0,
    @SerializedName("grnd_level")
    val groundLevel: Int = 0,
    @SerializedName("humidity")
    val humidity: Int = 0,
    @SerializedName("temp_kf")
    val temperatureKf: Double = 0.0
)

data class ForecastWind(
    @SerializedName("speed")
    val speed: Double = 0.0,
    @SerializedName("deg")
    val degree: Int = 0,
    @SerializedName("gust")
    val gust : Double = 0.0
)

data class ForecastRain(
    @SerializedName("3h")
    val heightInThreeHours: Double = 0.0
)

data class ForecastSnow(
    @SerializedName("3h")
    val heightInThreeHours: Double = 0.0
)

data class ForecastSys(
    @SerializedName("pod")
    val partOfDay: String = ""
)

3.在CustomEvent.kt中增加ForecastResponseEvent事件

class ForecastResponseEvent(val forecastResponse: ForecastResponse)

4.在RetrofitClient.kt中增加getForecastByCityName函数,用来MainActivity中调用请求接口:

    fun getForecastByCityName(cityName: String) {
        val call = weatherService.getForecastByCityName(cityName, API_KEY)
        call.enqueue(object : Callback<ForecastResponse> {
            override fun onResponse(call : Call<ForecastResponse>,
                response: Response<ForecastResponse>) {
                if(response.isSuccessful) {
                    val forecastData = response.body()
                    handleForecastData(forecastData)
                } else {
                    handleForecastFailure(response.message())
                }

            }

            override fun onFailure(call: Call<ForecastResponse>, t: Throwable) {
                handleForecastFailure(t.message!!)
            }
        })

5.并且增加了相应函数

  • handleForecastFailure接受消息字符串作为参数并将其与前缀一起打印出来。
  • handleForecastData接受一个ForecastResponse对象作为参数。它检查该对象是否为空,如果不为空,则创建一个对象ForecastResponseEvent并使用 EventBus 发布它。然后它调用该printForecastResponse函数并传入该ForecastResponse对象。
  • printForecastResponse接受一个ForecastResponse对象作为参数,并打印出该对象的各种属性,例如 、cod、message和cnt的大小forecastCellList。它还打印出对象的id和属性。nameforecastCity
    private fun handleForecastFailure(message: String) {
        println("handleForecastFailure:${message}")
    }

    private fun handleForecastData(forecastData: ForecastResponse?) {
        if(forecastData == null) return

        val forecastResponseEvent = ForecastResponseEvent(forecastData)
        EventBus.getDefault().post(forecastResponseEvent)		//这里发送了forecastResponseEvent

        printForecastResponse(forecastData)
    }

    private  fun printForecastResponse(forecastResponse: ForecastResponse) {
        println("cod:${forecastResponse.cod}")
        println("message:${forecastResponse.message}")
        println("cnt:${forecastResponse.cnt}")
        println("list:${forecastResponse.forecastCellList?.size}")
        println("city id:${forecastResponse.forecastCity?.id} name:${forecastResponse.forecastCity?.name}")
    }

6.在MainActivity中,处理forecastResponseEvent事件:

该函数是一个事件处理程序,在收到onReceiveForecastResponsea 时调用。ForecastResponseEvent它采用事件对象作为参数,其中包含预测响应数据。该函数调用该updateForecastList函数根据接收到的数据更新预测列表。

updateForecastList函数接受一个ForecastResponse对象作为参数。然后,它创建一个SimpleDateFormat对象来格式化预测响应中的日期和时间。该函数初始化一个空的可变列表data来存储格式化的预测数据。

然后,该函数会迭代 的预测单元格列表中的每个单元格forecastResponse。对于每个单元格,它都会创建一个字符串,oneLine其中包含格式化的日期和时间、温度、feel_like、天气主体和天气描述。通过减去常数值并将其转换为整数,将温度从开尔文转换为摄氏度kelvins。

每个oneLine字符串都会添加到data列表中。

最后,该函数创建一个ArrayAdapter以data列表为数据源的适配器,并将其设置为ListViewID 的适配器listViewTodayForcast。这将使用更新的预测数据更新列表视图。

    @RequiresApi(Build.VERSION_CODES.O)
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onReceiveForecastResponse(event: ForecastResponseEvent) {
        updateForecastList(event.forecastResponse)
    }
    
    private fun updateForecastList(forecastResponse: ForecastResponse) {
        val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ENGLISH)
        val data = mutableListOf<String>()
        for (cell in forecastResponse.forecastCellList!!) {
            val oneLine = "${simpleDateFormat.format(cell.dt*1000L)}\n" +
                    "temperature:${cell.main.temperature.minus(kelvins).toInt()}," +
                    "feel_like:${cell.main.feelsLike.minus(kelvins).toInt()},\n" +
                    "weather:${cell.weather.first().main},${cell.weather.first().description}"
            data.add(oneLine)
        }

        val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data)
        findViewById<ListView>(R.id.listViewTodayForcast).adapter = adapter
    }

7.我在主界面中增加了一个ListView用来显示forecast返回的数据

    <ListView
        android:id="@+id/listViewTodayForcast"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/textViewWeather"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

8.最后的结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/55418.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

我的创作纪念日——256天

机缘 最开始我写博客没有什么特别的原因&#xff0c;主要是因为以下几点&#xff1a; 练习自己的语言组织能力 记录自己学习生活中学到的知识 为和我同一个学习阶段的朋友提供帮助 事实上最开始我根本不指望我的博客有多少人看&#xff0c;主要是想找一个好的保存 Markdown 笔…

花费7元训练自己的GPT 2模型

在上一篇博客中&#xff0c;我介绍了用Tensorflow来重现GPT 1的模型和训练的过程。这次我打算用Pytorch来重现GPT 2的模型并从头进行训练。 GPT 2的模型相比GPT 1的改进并不多&#xff0c;主要在以下方面&#xff1a; 1. GPT 2把layer normalization放在每个decoder block的前…

PHP最简单自定义自己的框架(一)

为啥要定义自己的框架&#xff1a; 定制化需求&#xff1a;每个项目都有不同的需求和特点&#xff0c;使用通用的框架可能无法满足所有的要求。自定义框架可以根据具体需求进行定制&#xff0c;提供更加灵活和符合项目需求的解决方案。学习和成长&#xff1a;自定义框架是一个很…

STM32存储左右互搏 I2C总线读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线读写EEPROM ZD24C1MA 在较低容量存储领域&#xff0c;EEPROM是常用的存储介质&#xff0c;不同容量的EEPROM的地址对应位数不同&#xff0c;在发送字节的格式上有所区别。EEPROM是非快速访问存储&#xff0c;因为EEPROM按页进行组织&#xff0c;在连…

一文搞懂Redis架构演化之路

目录 从最简单的开始&#xff1a;单机版 Redis 数据持久化&#xff1a;有备无患 主从复制&#xff1a;多副本 哨兵&#xff1a;故障自动切换 分片集群&#xff1a;横向扩展 总结 这篇文章我想和你聊一聊 Redis 的架构演化之路。 现如今 Redis 变得越来越流行&#xff0c;…

图为科技加入深圳市智能交通行业协会 ,打 …

图为科技加入深圳市智能交通行业协会&#xff0c;打造智能交通新生态&#xff01; 交通是国民经济发展的“大动脉”&#xff0c;交通拥堵、事故频发等问题不仅影响了人们的出行体验&#xff0c;也对经济的发展产生了负面影响。安全、高效、便捷的出行&#xff0c;一直是人们的…

【Unity实用插件篇】| 学会使用 可编程瓦片Tile Map,快速搭建2D地图

前言【Unity 实用插件篇】| 学会使用 可编程瓦片Tile Map,快速搭建2D地图一、导入 Tile Map Editor二、创建调色板 Tile Palette三、快速绘制地图四、TilePalette 调色板功能介绍五、TileMap 相关组件属性介绍GirdTilemapTilemap Renderer 瓦片地图渲染器Tile Assets 瓦片资源…

【Git】分支管理策略

文章目录 分支策略bug分支-master分支出现bug怎么办删除临时分⽀小结 分支策略 在实际开发中&#xff0c;我们应该按照⼏个基本原则进⾏分⽀管理&#xff1a; 1.master分⽀应该是⾮常稳定的&#xff0c;也就是仅⽤来发布新版本&#xff0c;平时不能在上⾯⼲活 2.⼲活都在dev…

Reinforcement Learning with Code 【Code 2. Tabular Sarsa】

Reinforcement Learning with Code 【Code 2. Tabular Sarsa】 This note records how the author begin to learn RL. Both theoretical understanding and code practice are presented. Many material are referenced such as ZhaoShiyu’s Mathematical Foundation of Rei…

Elasticsearch 全文检索 分词检索-Elasticsearch文章四

文章目录 官方文档地址refercence文档全文搜索体系match简单查询match 多词/分词单字段分词match多个词的逻辑控制match的匹配精度match_pharse_prefix分词前缀方式match_bool_prefixmulti_match多字段匹配 query string类型Interval类型DSL查询之Term详解聚合查询之Bucket聚合…

RTT(RT-Thread)线程管理(1.2W字详细讲解)

目录 RTT线程管理 线程管理特点 线程工作机制 线程控制块 线程属性 线程状态之间切换 线程相关操作 创建和删除线程 创建线程 删除线程 动态创建线程实例 启动线程 初始化和脱离线程 初始化线程 脱离线程 静态创建线程实例 线程辅助函数 获得当前线程 让出处…

【LeetCode】446. 等差数列划分II -- 子序列

题目链接 文章目录 1. 思路讲解1.1 dp表的创建1.2 状态转移方程1.3 使用哈希表找到k1.4 初始化1.5 返回值1.6 该题坑爹的一点 2. 代码编写 1. 思路讲解 我们要知道以某个位置为结尾的子序列的数量&#xff0c;可以通过它的以上一位置的为结尾的子序列的数量得知&#xff0c;也…

css3 hover border 流动效果

/* Hover 边线流动 */.hoverDrawLine {border: 0 !important;position: relative;border-radius: 5px;--border-color: #60daaa; } .hoverDrawLine::before, .hoverDrawLine::after {box-sizing: border-box;content: ;position: absolute;border: 2px solid transparent;borde…

Linux第八章之进程概念

一、冯诺依曼体系结构 关于冯诺依曼&#xff0c;必须强调几点&#xff1a; 这里的存储器指的是内存不考虑缓存情况&#xff0c;这里的CPU能且只能对内存进行读写&#xff0c;不能访问外设(输入或输出设备)外设(输入或输出设备)要输入或者输出数据&#xff0c;也只能写入内存或…

加强Web应用程序安全:防止SQL注入

数据库在Web应用程序中存储和组织数据时起着至关重要的作用&#xff0c;它是存储用户信息、内容和其他应用程序数据的中央存储库。而数据库实现了高效的数据检索、操作和管理&#xff0c;使Web应用程序能够向用户提供动态和个性化的内容。然而&#xff0c;数据库和网络应用程序…

SQL Developer中的Active Data Guard

这篇文章 Display Data Guard configuration in SQL Developer 中&#xff0c;用SQL Developer展示了多种ADG的拓扑。 今天自己也试了一下&#xff0c;还蛮简单的&#xff0c;其实最麻烦的部分在于搭建一个ADG环境。 假设我已有一个ADG环境&#xff0c;即最典型的环境&#x…

简要介绍 | 生成模型的演进:从自编码器(AE)到变分自编码器(VAE)和生成对抗网络(GAN),再到扩散模型

注1:本文系“简要介绍”系列之一,仅从概念上对生成模型(包括AE, VAE, GAN,以及扩散模型)进行非常简要的介绍,不适合用于深入和详细的了解。 生成模型的演进:从自编码器(AE)到变分自编码器(VAE)和生成对抗网络(GAN),再到扩散模型 一、背景介绍 生成模型在机器学习领域…

数据结构 | 线性数据结构——双端队列

目录 一、何谓双端队列 二、双端队列抽象数据类型 三、用Python实现双端队列 四、回文检测器 一、何谓双端队列 双端队列是与队列类似的有序集合。它有一前、一后两端&#xff0c;元素在其中保持自己的位置。与队列不同的是&#xff0c;双端队列对在哪一端添加和移除元素没…

Flask-SocketIO

一、简介&#xff1a; Flask-SocketIO使Flask应用程序可以实现客户端和服务器之间的低延迟双向通信。客户端应用程序可以使用 Javascript、Python、C、Java和Swift中的任何SocketIO客户端库或任何其他兼容客户端来建立与服务器的永久连接。 二、安装&#xff1a; pip instal…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(18)-Fiddler如何接口测试,妈妈再也不担心我不会接口测试了

1.简介 Fiddler最大的优势在于抓包&#xff0c;我们大部分使用的功能也在抓包的功能上&#xff0c;fiddler做接口测试也是非常方便的。 领导或者开发给你安排接口测试的工作任务&#xff0c;但是没有给你接口文档&#xff08;由于开发周期没有时间出接口文档&#xff09;&…