You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin调用天气接口URL.readText返回null报JSONException

问题解决方案:Android Kotlin请求OpenWeatherMap接口返回null及JSON解析异常

问题根因

主要由以下几个常见问题共同导致:

  • 明文HTTP请求被系统拦截:Android 9(API 28)及以上版本默认禁止明文HTTP流量,你当前使用的http://接口会被系统直接拦截,请求抛出异常被catch后返回null,浏览器没有该限制所以可以正常拿到响应
  • 请求参数未做URL编码:如果定位参数包含空格、中文或特殊字符,直接拼接URL会导致请求非法,浏览器会自动完成参数编码,代码中无编码逻辑会导致请求失败
  • 异常被直接吞掉无排查依据:当前代码捕获所有异常后直接返回null,无法定位具体请求错误原因
  • 空响应直接解析逻辑不合理:response为null时你创建了空JSONObject,后续直接调用getJSONObject方法找不到对应字段就会抛出JSONException

解决方案

步骤1:修复HTTP明文限制(优先选方案1)

  • 方案1:直接替换为HTTPS接口,OpenWeatherMap原生支持HTTPS,将请求地址的http://api.openweathermap.org修改为https://api.openweathermap.org即可
  • 方案2:如果必须使用HTTP,新增网络安全配置放开限制:
    1. 在res/xml目录下新建network_security_config.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">api.openweathermap.org</domain>
    </domain-config>
</network-security-config>
  1. 在AndroidManifest.xml的<application>标签中添加属性:android:networkSecurityConfig="@xml/network_security_config"

步骤2:确认网络权限配置

检查AndroidManifest.xml中已添加网络权限:

<uses-permission android:name="android.permission.INTERNET" />

步骤3:优化网络请求函数

suspend fun getWeatherResponse(locationCode: String, apiKey: String): String? {
    return withContext(Dispatchers.IO) {
        // 对定位参数做URL编码,兼容特殊字符场景
        val encodedLocation = URLEncoder.encode(locationCode, StandardCharsets.UTF_8.name())
        val apiUrl = "https://api.openweathermap.org/data/2.5/weather" +
                "?q=$encodedLocation&appid=$apiKey"
        return@withContext try {
            Log.d("WeatherRequest", "请求地址:$apiUrl") // 调试用,可确认拼接的URL是否正确
            URL(apiUrl).readText(StandardCharsets.UTF_8)
        } catch (ex: Exception) {
            Log.e("WeatherRequest", "请求失败", ex) // 打印异常便于排查问题
            null
        }
    }
}

步骤4:优化JSON解析逻辑避免崩溃

val response = getWeatherResponse(location, apiKey)
// 先判断响应是否合法,空响应直接走失败逻辑
if (response.isNullOrBlank()) {
    // 此处添加请求失败提示逻辑,比如弹Toast
    Toast.makeText(context, "网络请求失败,请稍后重试", Toast.LENGTH_SHORT).show()
    return@coroutineScope // 终止后续解析流程
}
val jsonWeatherObj = JSONObject(response)
// 解析时用optXxx代替getXxx,避免字段缺失直接崩溃,可按需添加失败提示
val main = jsonWeatherObj.optJSONObject("main") ?: run {
    Toast.makeText(context, "天气数据解析失败", Toast.LENGTH_SHORT).show()
    return@coroutineScope
}
val sys = jsonWeatherObj.optJSONObject("sys") ?: return@coroutineScope
val wind = jsonWeatherObj.optJSONObject("wind") ?: return@coroutineScope
val weather = jsonWeatherObj.optJSONArray("weather")?.optJSONObject(0) ?: return@coroutineScope

// 字段获取也可以用optString设置默认值,提升容错性
val temp = "${main.optString("temp", "0")}°C"
val tempMin = "Min Temp: ${main.optString("temp_min", "0")}°C"
val tempMax = "Max Temp: ${main.optString("temp_max", "0")}°C"
// 其余字段按相同逻辑处理即可

内容的提问来源于stack exchange,提问作者exactly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 19:54:03