日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

彩云天气JSON数据解析

發布時間:2023/12/3 综合教程 67 生活家
生活随笔 收集整理的這篇文章主要介紹了 彩云天气JSON数据解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JSON數據解析——彩云天氣api

彩云天氣API

首先在彩云天氣官網注冊一個賬號,注冊地址是:

https://dashboard.caiyunapp.com/

注冊之后可查看API文檔

天氣app所需數據

1、地區數據

訪問地址接口可查詢到全球絕大多數地區的數據信息

https://api.caiyunapp.com/v2/place?query=北京&token={token}&lang=zh_CN

query參數指定的是要查詢的關鍵字(如地名),token傳入剛剛申請到的令牌值。服務器會返回我們一段JSON格式的數據,我們所需獲取的數據有name(該地區的名字)、location(該地區的經緯度)、formatted_address(該地區的地址)

{"status":"ok","query":"北京","places":[{"name":"北京南站","formatted_address":"中國 北京市 豐臺區 永外大街車站路12號","location":{"lat":39.865246,"lng":116.378517}},{"name":"北京西站","formatted_address":"中國 北京市 豐臺區 蓮花池東路118號","location":{"lat":39.89491,"lng":116.322056}},{"name":"北京站","formatted_address":"中國 北京市 東城區 毛家灣胡同甲13號","location":{"lat":39.902842,"lng":116.427341}},{"name":"北京北站","formatted_address":"中國 北京市 西城區 北濱河路1號","location":{"lat":39.944876,"lng":116.353063}},{"name":"北京東站(地鐵站)","formatted_address":"中國 北京市 朝陽區 (在建)28號線","location":{"lat":39.902267,"lng":116.482682}}]
}

其展示效果如下:

2、實時天氣數據

實時天氣信息API接口:

https://api.caiyunapp.com/v2.5/{token}/101.6656,39.2072/realtime

token仍是剛剛傳入的令牌值,101.6656,39.2072分別是維度和經度,中間用逗號隔開,這樣服務器就會把該地區的實時天氣信息以JSON格式返回給我們,我們從中提取需要的數據,realtime中包含的就是當前地區的實時天氣信息,其中temperature表示當前的溫度,skycon表示當前的天氣情況,air_quality中包含一些空氣質量的數據,這里使用aqi的值作為空氣質量指數顯示在界面上

{"status":"ok","result":{"realtime":{"temperature":17.0,"skycon":"PARTLY_CLOUDY_DAY","air_quality":{"aqi":{"chn":78}}}}
}

其展示效果如下:

3、未來幾天的天氣數據

未來幾天的天氣信息API接口

https://api.caiyunapp.com/v2.5/{token}/116.378517,39.865246/daily.json

這個接口返回的數據也比較復雜,我們依舊只需提取需要的數據
daily包含的就是當前地區未來幾天的天氣信息,temperature表示未來幾天的溫度值,skycon表示未來幾天的天氣情況,life_index中包含一些生活指數,coldRish表示感冒指數,CarWashing表示洗車指數,ultraviolet表示紫外線指數,dressing表示穿衣指數

{“status:"  "ok","result": {"daily": {"temperature": [ {"max":18.0,"min":9.0},...],"skycon":[{"date":"2022-03-28T00:00+08:00","value":"PARTLY_CLOUDY_DAY"},...]"life_index":{"coldRisk":[{"desc":"極易發"},...],"carWashing"[{"desc":"較不適宜"},...],"ultraviolet":[{"desc":"強"},...],"dressing":[{"desc:"冷""},...]}}}
}

其展示效果如下:

使用retrofit請求api獲取數據

以上述中地區部分為例

{"status":"ok","query":"北京","places":[{"name":"北京南站","formatted_address":"中國 北京市 豐臺區 永外大街車站路12號","location":{"lat":39.865246,"lng":116.378517}},{"name":"北京西站","formatted_address":"中國 北京市 豐臺區 蓮花池東路118號","location":{"lat":39.89491,"lng":116.322056}},{"name":"北京站","formatted_address":"中國 北京市 東城區 毛家灣胡同甲13號","location":{"lat":39.902842,"lng":116.427341}},{"name":"北京北站","formatted_address":"中國 北京市 西城區 北濱河路1號","location":{"lat":39.944876,"lng":116.353063}},{"name":"北京東站(地鐵站)","formatted_address":"中國 北京市 朝陽區 (在建)28號線","location":{"lat":39.902267,"lng":116.482682}}]
}

分析這段json數據:

  • 第一層是一個花括號,即jsonObject對象,其中有status、query屬性以及一個places的JSON數組(中括號為JSONArray數組)
  • 第二層places的JSON數組,其中有name、formatted_address、location
  • 第三層location有lat和lng兩個屬性

kotlin代碼實現請求數據

我們在定義這一部分數據模型時,對每一層都需要有一個數據類,按照以上分析的JSON格式來定義
新建一個PlaceResponse.kt文件,并在這個文件中編寫如下代碼

/*** 第一層:status和places的JSON數組*/
data class PlaceResponse(val status: String, val places: List<Place>)
/*** 第二層:name、location、formatted_address* 由于JSON中的一些字段命名可能與kotlin的命名規范不一致,所以使用了@SerializedName注解* @ SerializedName注解使JSON字段和kotlin字段之間建立映射關系*/
data class Place(val name: String, val location: Location,@SerializedName("formatted_address") val address: String)
/*** 第三層:lng、lat*/
data class Location(val lng: String, val lat: String)

定義好數據模型之后,我們可以開始編寫網絡層相關的代碼了。首先定義一個用于訪問彩云天氣城市搜索API的Retrofit接口

還記得上面那個測試地區JSON數據的API接口嗎?就是使用剛剛的接口,不過我們需要向其中傳入我們的“query”和“token”以便可以通過搜索框查到大部分地區的數據

interface PlaceService {/*** 當調用searchPlaces時,Retrofit就會自動發起一個GET請求,去訪問GET注解中配置的地址* 其中token和lang參數都是不變的,可以直接固定寫在注解中* query參數是需要動態指定的,這里使用@Query注解的方式來實現* * 另外searchPlaces的返回值被聲明成Call<PlaceResponse>,這樣JSON數據就會自動解析成PlaceResponse對象*/@GET("v2/place?token=${SunnyWeatherApplication.TOKEN}&lang=zh_CN")fun searchPlaces(@Query("query") query: String) : Call<PlaceResponse>
}

現在,我們就可以開始測試進行連接通信了
新建一個Test測試類,寫上主函數進行測試,需要注意的是,kotlin的主函數需要在上方加上@JvmStatic注解

class Test {companion object{//BASE_URL不會變,直接傳入我們所需的彩云天氣的URL用于指定Retrofit的根路徑private const val BASE_URL = "https://api.caiyunapp.com/"//main函數入口@JvmStaticfun main(args: Array<String>) {//從控制臺輸入要查詢的地區名稱val placeStr = readLine()//獲取PlaceService接口的動態代理對象val retrofit = Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build()//創建API接口對象val placeService = retrofit.create(PlaceService::class.java)//創建一個請求對象val call: Call<PlaceResponse> = placeService.searchPlaces(placeStr!!)//開始進行連接請求call.enqueue(object : Callback<PlaceResponse> {override fun onResponse(call: Call<PlaceResponse>,response: Response<PlaceResponse>) {val placeResponse = response.body();if (placeResponse?.status == "ok"){val places = response.body()?.placesfor (place in places!!){val name = place.nameval address = place.addressval location = place.locationval lng = location.lngval lat = location.latprintln("地名:${name},  地址:${address},  經緯度(${lng},${lat})")}}}override fun onFailure(call: Call<PlaceResponse>, t: Throwable) {TODO("Not yet implemented")println("error")}})}}
}

以下就是服務器返回的數據被自動解析成JSON對象的結果

我們對數據進行進一步提取后就完成我們本次的網絡請求了

上面Test類只是進行一個簡單測試,在實際項目(以《第一行代碼》彩云天氣開發為實例進行學習)中我們不可能每次都去寫一個單獨的對象去獲取Service接口

因此在項目中,為了更好的使用Service接口,Retrofit構建器一般會使用以下寫法

新建一個ServiceCreator 單例類

object ServiceCreator {//BASE_URL不會變,直接傳入我們所需的彩云天氣的URL用于指定Retrofit的根路徑private const val BASE_URL = "https://api.caiyunapp.com/"private val retrofit = Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build()/*** 提供一個外部可見的create方法并接收一個class類型參數* 這樣經過封裝之后,通過參數的不同可以創建相應的Service接口,而不用為每一個類都單獨寫一個構造器*/fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)inline fun <reified T> create(): T = create(T::class.java)
}

接下來需要定義一個統一的網絡數據源訪問入口,對所有的網絡請求的API進行封裝。

object SunnyWeatherNetwork {//使用ServiceCreator創建一個placeService接口的動態代理對象private val placeService = ServiceCreator.create(PlaceService::class.java)/*** 當外部調用SunnyWeatherNetwork的searchPlaces時,retrofit會立即發出網絡請求* 同時當前的協程也會被阻塞住,知道服務器響應我們的請求之后* await()函數會將解析出來的數據模型對象取出并返回*///定義searchPlaces函數并調用searchPlaces()方法以發起搜索城市數據請求suspend fun searchPlaces(query: String) = placeService.searchPlaces(query).await()private suspend fun <T> Call<T>.await(): T {//suspend掛起函數關鍵字//await()是一個掛起函數,給它聲明一個泛型T,并將await()函數定義成call<T>的擴展函數return suspendCoroutine { continuation ->enqueue(object : Callback<T> {//直接調用enqueue()方法讓Retrofit發起網絡請求override fun onResponse(call: Call<T>, response: Response<T>) {val body = response.body()if (body != null) continuation.resume(body)else continuation.resumeWithException(RuntimeException("response body is null"))}override fun onFailure(call: Call<T>, t: Throwable) {continuation.resumeWithException(t)}})}}
}

這樣每次需要使用某個API接口時,只需要在SunnyWeatherNetwork 中創建相關的接口對象傳入對應的類型參數就可以獲取到了
那么現在我們對獲取地區數據進行測試,其實只需要通過SunnyWeatherNetwork.searchPlaces()就能得到地區數據了

因為searchPlaces()被設置為suspend掛起,因此給剛剛的main()加上一個runBlocking(調用了 runblocking 的線程會阻塞直到內部的協程執行完畢)這樣就可以執行了

companion object{@JvmStaticfun main(args: Array<String>) = runBlocking{//從控制臺輸入要查詢的地區名稱val placeStr = readLine()/*** 在SunnyWeatherNetwork中已經創建了placeService接口的動態代理對象* 若要使用別的接口,也只需要在SunnyWeatherNetwork添加方法即可*/val placeResponse = SunnyWeatherNetwork.searchPlaces(placeStr!!)if (placeResponse.status == "ok"){val places = placeResponse.placesfor (place in places){val name = place.nameval address = place.addressval location = place.locationval lng = location.lngval lat = location.latprintln("地名:${name},  地址:${address},  經緯度(${lng},${lat})")}}}
}

其實現在真正發送請求只需要一行代碼:

val placeResponse = SunnyWeatherNetwork.searchPlaces(placeStr!!)

而且現在調用其他的API接口都可以按照這種模式進行編寫

總結

以上是生活随笔為你收集整理的彩云天气JSON数据解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。