#c# #android #api #unity3d #game-engine
#c# #Android #API #unity3d #игровой движок
Вопрос:
Я пытался использовать weatherbit.io API для доступа к информации AQI в моем приложении для Android. Скрипт AqiInfoScript
используется для доступа к API, а Update AQI
скрипт используется для вывода значения.
AqiInfoScript:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using SimpleJSON;
public class AqiInfoScript : MonoBehaviour
{
private float timer;
public float minutesBetweenUpdate;
private float latitude;
private float longitude;
private bool locationInitialized;
public static string cityName;
public static double currentAqi;
private readonly string baseWeatherbitURL = "https://api.weatherbit.io/v2.0/current/airquality?";
private readonly string key = "*********************";
public void Begin()
{
latitude = GPS.latitude;
longitude = GPS.longitude;
locationInitialized = true;
}
void Update()
{
if (locationInitialized)
{
if (timer <= 0)
{
StartCoroutine(GetAqi());
timer = minutesBetweenUpdate * 60;
}
else
{
timer -= Time.deltaTime;
}
}
}
private IEnumerator GetAqi()
{
string weatherbitURL = baseWeatherbitURL "lat=" latitude "amp;lon=" longitude "amp;key="
key;
UnityWebRequest aqiInfoRequest = UnityWebRequest.Get(weatherbitURL);
yield return aqiInfoRequest.SendWebRequest();
//error
if (aqiInfoRequest.isNetworkError || aqiInfoRequest.isHttpError)
{
Debug.LogError(aqiInfoRequest.error);
yield break;
}
JSONNode aqiInfo = JSON.Parse(aqiInfoRequest.downloadHandler.text);
cityName = aqiInfo["city_name"];
currentAqi = aqiInfo["data"]["aqi"];
}
}
Скрипт UpdateAQI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UpdateAQI : MonoBehaviour
{
public Text airquality;
//public Text coordinates;
private void Update()
{
airquality.text = "Current Aqi: " AqiInfoScript.currentAqi.ToString();
}
}
Текущий вывод: Текущий AQI: 0
Желаемый результат: Текущий AQI: 129.0000
Комментарии:
1. вы уверены, что
Begin
вызывается? ПослеcurrentAqi = aqiInfo["data"]["aqi"];
можете ли вы добавитьDebug.Log($"New data available: ${currentAqi}");
? Вы также пытались явно вызватьagiInfo["data"]["aqi"].AsDouble
? .. вы также не должны публиковать здесь реальные ключи2. В общем, я бы не делал этого в
Update
, а скорее управлял событиями. Запустите следующую загрузку после завершения или сбоя. Обновляйте текстовый компонент только в том случае, если были получены новые данные3. 1. Функция Begin уже присутствовала в
GPS
скрипте какaqiInfoScript.Begin();
2. Я добавил Debug. Журнал 3. Также явно вызванныйagiInfo["data"]["aqi"]
, и все они представили тот же результат, что и до 4. Прошу прощения за ключ, я боролся с этим уже несколько дней, я совершенно забыл о ключе 5. Что касается вашего второго запроса, я сначала хотел убедиться, что я действительно получаю данные перед очисткой кода, но этого не происходит даже с самыми простыми программами:(4. Но на всякий случай это означает, что это не имеет никакого отношения к вашему второму скрипту, но ошибка уже заключается в данных, которые вы получаете от API… вы на 100% уверены, что в ключах для
currentAqi = aqiInfo["data"]["aqi"];
нет опечатки? Имеет ли полученный json точное совпадение имен полей? Не могли бы вы показать нам результатDebug.Log(aqiInfoRequest.downloadHandler.text);
?5. Ниже приведена ссылка на weatherbit. домашняя страница ввода-вывода, которая содержит образец файла JSON
https://www.weatherbit.io/api/airquality-current#:~:text=This Air Quality API returns,(USA and EU only)
, я проверял это снова и снова.aqi
Находится подdata
классом. Нет совпадающих имен полей.
Ответ №1:
Проблема
Как я вижу, API возвращает для вашего запроса, например для lat=42, lon=-7
следующего JSON
{
"data":[
{
"mold_level":1,
"aqi":54,
"pm10":7.71189,
"co":298.738,
"o3":115.871,
"predominant_pollen_type":"Molds",
"so2":0.952743,
"pollen_level_tree":1,
"pollen_level_weed":1,
"no2":0.233282,
"pm25":6.7908,
"pollen_level_grass":1
}
],
"city_name":"Pías",
"lon":-7,
"timezone":"Europe/Madrid",
"lat":42,
"country_code":"ES",
"state_code":"55"
}
Как вы можете видеть, "data"
на самом деле это массив. Вы рассматриваете его как единственное значение.
За кулисами
К сожалению, используемая вами библиотека SmipleJson довольно подвержена ошибкам, потому что она не выдает никаких исключений из-за опечаток, а скорее молчаливо завершает работу и использует значение по умолчанию.
Вы можете увидеть это, например, в
public override JSONNode this[string aKey]
{
get
{
if (m_Dict.ContainsKey(aKey))
return m_Dict[aKey];
else
return new JSONLazyCreator(this, aKey);
}
....
}
и
public static implicit operator double(JSONNode d)
{
return (d == null) ? 0 : d.AsDouble;
}
Решение
Скорее это должно быть
cityName = aqiInfo["city_name"];
currentAqi = aqiInfo["data"][0]["aqi"].AsDouble;
Debug.Log($"cityName = {cityName}ncurrentAqi = {currentAqi}");
В общем, я бы предложил использовать JsonUtility.FromJson
и скорее реализовать требуемую структуру данных на c #, например:
[Serializable]
public class Data
{
public int mold_level;
public double aqi;
public double pm10;
public double co;
public double o3;
public string predominant_pollen_type;
public double so2;
public int pollen_level_tree;
public int pollen_level_weed;
public double no2;
public double pm25;
public int pollen_level_grass;
}
[Serializable]
public class Root
{
public List<Data> data;
public string city_name;
public int lon;
public string timezone;
public int lat;
public string country_code;
public string state_code;
}
и тогда вы бы использовали
var aqiInfo = JsonUtility.FromJson<Root>(aqiInfoRequest.downloadHandler.text);
cityName = aqiInfo.city_name;
currentAqi = aqiInfo.data[0].aqi;
Debug.Log($"cityName = {cityName}ncurrentAqi = {currentAqi}");
Для меня, как сказано с фиктивными значениями lat=42, lon=-7
, оба раза он выводится, как ожидалось
cityName = Pías
currentAqi = 54
UnityEngine.Debug:Log(Object)
<GetAqi>d__18:MoveNext() (at Assets/Example.cs:109)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
Комментарии:
1. Я использовал ваш точный
GetAqi
пример сценария вStart
и просто жестко запрограммировал,lat=42;
иlon=-7;
если я это сделаюDebug.Log($"cityName = {cityName}ncurrentAqi = {currentAqi}");
, я получу ожидаемый результат печати.. независимо от того, какую из двух библиотек json я использую.2. Большое вам спасибо @derHugo . Приложение по-прежнему возвращает,
Current Aqi: 0
но теперь я попробуюJSONUtility
и реализую его таким образом. У меня есть одно сомнение, которое может быть или не быть уместным здесь, но weatherbit. io имеет что-то вроде Все параметры должны быть предоставлены API качества воздуха в качестве параметров строки запроса. может ли это быть какой-то проблемой?3. Извините, что спрашиваю об этом, но что означает «в начале»? должен ли я поместить свой код в void start()? В этот момент я паникую!
4. Я использовал
Start
, поскольку это вызывается автоматически при запуске приложения… Просто сделал это для тестирования .. если вы говорите, что куда-то звонитеBegin
, тогда все должно быть в порядке… вы вообще получаете журнал отладки из процедуры загрузки? .. Возможно, ваша процедура никогда не запускается5. Да, я вызываю
Begin
, как только получу значения lat / lon изGPS
скрипта. Я протестировал и обнаружил, что он точно фиксирует значения широты / lon. Я попытаюсь поместить свойCoroutine
вBegin
сам и посмотреть, станет ли он лучше. Нет, я не получаю никаких файлов отладки, поскольку я вручную создаю APK и отправляю его на свой телефон. Есть предложения с вашей стороны? Может быть, я должен уничтожить все это и начать сверху.