【Android】实现天气预报·视频
首先说明,这是极简版,简单到无可附加!只写天气预报原理。
原理其实就是
【请求】 中国的、较完整的 天气预报网络接口,
【解析】返回的 JSON 数据,
【呈现】数据。
仅此而已,别无其他。
源码下载
WeatherDemo
实现效果图
前提
请先阅读我在Bilibili发表的两篇文章:
《【Android】XHttp2网络请求库的源码浅析与快速上手总结》
《解决XHTTP2 自定义引入不方便的问题》
接下来我会默认你已经熟读了我上述两篇文章,然后开始天气预报原理的简单叙述
正文
首先是开发工具版本相关:
我用的是 AndroidStudio 4.2.2 + gradle-7.0.2-bin.zip + gradle:4.1.0
然后是依赖引入:
引入两个模块到工程
include ':library-EditSpiner',':library-xhttp2'
接下来我们依赖两个模块到项目app的dependencies
implementation project(":library-xhttp2")
implementation project(":library-EditSpiner")
sync一下gradle即可
接下来我们看一下源码的左侧目录树的样子
其中
Bean已经在 《【Android】XHttp2网络请求库的源码浅析与快速上手总结》 里面介绍过了,就是根据接口返回值一一对应创建的 JavaBean,又叫 Entity,又叫 POJO
DoubleClickHelper就是一个单纯的预防短时间内多次点击的帮助类,接口完全免费,大家不要无节制的请求,无需多言。
MyApplication里面是进行XHttp2的初始化,也不用多说。
主要是看一下 MainActivity
因为 Xhttp2 的自动解析功能过于强大,因此代码属实不长,我直接粘贴到下面
public class MainActivity extends AppCompatActivity {
private String cityName;
private TextView tvContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1、读取 XML 数据
String[] cityCodeArray = getResources().getStringArray(R.array.cityCode);
String[] cityNameArray = getResources().getStringArray(R.array.cityName);
List<String> cityNameList = Arrays.asList(cityNameArray);
// 2、将数据填充给 Spinner 控件
EditSpinner editSpinner = findViewById(R.id.editspinner);
editSpinner.setItemData(cityNameList);
tvContent = findViewById(R.id.tv_content);
Button btSearch = findViewById(R.id.bt_search);
// 3、按钮点击响应事件
btSearch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 防止快速点击
if (DoubleClickHelper.isOnDoubleClick(3000)) {
Toast.makeText(MainActivity.this, "查询太频繁,手别抖!", Toast.LENGTH_SHORT).show();
return;
}
cityName = editSpinner.getText();
if (TextUtils.isEmpty(cityName)) {
return;
}
// 根据填写的城市名称查到对应的城市代码
int index = cityNameList.indexOf(cityName);
if (index == -1) {
Toast.makeText(MainActivity.this, "输入城市名称未录入系统,请重新输入", Toast.LENGTH_SHORT).show();
return;
}
String url = "http://t.weather.itboy.net/api/weather/city/" + cityCodeArray[index];
// Xhttp2 请求网络
XHttp.get(url)
.syncRequest(false)
.execute(new CallBackProxy<Body<ResponseData>, ResponseData>(
new SimpleCallBack<ResponseData>() {
@Override
public void onSuccess(ResponseData data) {
// 处理 data
dealWithData(data);
}
@Override
public void onError(ApiException e) {
// 处理异常
}
}
) {});//最后一定要有 {} 否则解析失败
}
});
}
@SuppressLint("SetTextI18n")
private void dealWithData(ResponseData data) {
if (data == null) {
Toast.makeText(MainActivity.this, "结果异常!", Toast.LENGTH_SHORT).show();
return;
}
Forecast todayForecast = data.getForecast().get(0);
String today = buildForecastString(todayForecast, "今天");
Forecast tomorrowForecast = data.getForecast().get(1);
String tomorrow = buildForecastString(tomorrowForecast, "明天");
tvContent.setText(today + tomorrow);
}
private String buildForecastString(Forecast forecast, String day) {
return day + "【" + cityName + "】天气" + "n" +
"日期:" + forecast.getYmd() + "丨" +
forecast.getWeek() + ";n" +
"天气类型:" + forecast.getType() + ";n" +
"最高温度:" + forecast.getHigh() + ";n" +
"最低温度:" + forecast.getLow() + ";n" +
"刮风情况:" + forecast.getFl() + "丨" +
forecast.getFx() +
";n" +
"天气建议:" + forecast.getNotice() + ";nnn";
}
}
当然,其中还涉及到了Android中的Xml引入Array的方法、以及允许调用Http请求的XML配置。简单提一下吧
Android中的Xml引入Array的方法
因为我们要选择全国的 市、区、县 进行天气预报,比如 【北京市】,但是这个是汉字,天气预报接口需要的是对应的城市编码,比如北京市是101010100,详情对应请看:《天气预报调用接口》
String url = "http://t.weather.itboy.net/api/weather/city/" + 城市编码;
怎样做既能知道 城市名称,又能知道 城市编码?最好的是有一个现成的 JSON,每个都城市名称和编码都对应好,然后我们读取 JSON 数据,转成一个一个得对象即可。但是,就当前这个天气接口来说,我没有发现这个写好的 JSON。而是只有【101010100=北京】这样的对应方式。看到这样的对应方式,我直观的想法就是造两个数组,一个数组存 城市编码,另一个数组存 城市名称。这样我们选好城市名称后就能根据城市名称的 index 去查找到对应的 城市编码。于是就有了 res/values/arrays.xml 里面的两个数组了。为了避免影响本文阅读,我把它俩粘贴到文章的最后面。我查了一下,有台湾,大家可以放心使用,确实是中国的、较完整的接口。
Android允许调用Http请求的XML配置
Android SDK24 起,不再默认允许调用 HTTP 请求网络,如果的确需要请求 HTTP 网络,需要特殊在 AndroidManifest.xml 里进行特殊声明,如下图所示:
配置内容在 res/xml/network_security_config.xml 里面,具体内容如下
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
经过这样配置,我们就可以在 Android SDK 大于 24 的时候 访问 HTTP 链接了。
结尾
代码过于简洁,我想我做到这里也就足够了,毕竟师傅领进门了,给你留点进步的空间。正所谓,十分能力使三分,留作七分给后人!
【参考文章】
《天气预报调用接口》
两个数组
<resources>
<string-array name="cityCode">
<item>101010100</item>
<item>101010200</item>
<item>101010300</item>
<item>101010400</item>
<item>101010500</item>
<item>101010600</item>
<item>101010700</item>
<item>101010800</item>
<item>101010900</item>
<item>101011000</item>
<item>101011100</item>
<item>101011200</item>
<item>101011300</item>
<item>101011400</item>
<item>101011500</item>
<item>101011600</item>
<item>101011700</item>
<item>101011800</item>
<item>101011900</item>
<item>101012000</item>
<item>101012100</item>
<item>101020100</item>
<item>101020200</item>
<item>101020300</item>
<item>101020400</item>
<item>101020500</item>
<item>101020600</item>
<item>101020700</item>
<item>101020800</item>
<item>101020900</item>
<item>101021000</item>
<item>101021100</item>
<item>101021101</item>
<item>101021102</item>
<item>101021200</item>
<item>101021300</item>
<item>101030100</item>
<item>101030200</item>
<item>101030300</item>
<item>101030400</item>
<item>101030500</item>
<item>101030600</item>
<item>101030700</item>
<item>101030800</item>
<item>101030900</item>
<item>101031000</item>
<item>101031100</item>
<item>101031200</item>
<item>101031300</item>
<item>101031400</item>
<item>101040100</item>
<item>101040200</item>
<item>101040300</item>
<item>101040400</item>
<item>101040500</item>
<item>101040600</item>
<item>101040700</item>
<item>101040800</item>
<item>101040900</item>
<item>101041000</item>
<item>101041100</item>
<item>101041200</item>
<item>101041300</item>
<item>101041400</item>
<item>101041500</item>
<item>101041600</item>
<item>101041700</item>
<item>101041800</item>
<item>101041900</item>
<item>101042000</item>
<item>101042100</item>
<item>101042200</item>
<item>101042300</item>
<item>101042400</item>
<item>101042500</item>
<item>101042600</item>
<item>101042700</item>
<item>101042800</item>
<item>101042900</item>
<item>101043000</item>
<item>101043100</item>
<item>101043200</item>
<item>101043300</item>
<item>101043400</item>
<item>101043500</item>
<item>101043600</item>
<item>101043700</item>
<item>101050101</item>
<item>101050102</item>
<item>101050103</item>
<item>101050104</item>
<item>101050105</item>
<item>101050106</item>
<item>101050107</item>
<item>101050108</item>
<item>101050109</item>
<item>101050110</item>
<item>101050111</item>
<item>101050112</item>
<item>101050113</item>
<item>101050201</item>
<item>101050202</item>
<item>101050203</item>
<item>101050204</item>
<item>101050205</item>
<item>101050206</item>
<item>101050207</item>
<item>101050208</item>
<item>101050209</item>
<item>101050210</item>
<item>101050301</item>
<item>101050302</item>
<item>101050303</item>
<item