文章目录

  • 显示天气信息
    • 解析天气数据
      • basic
      • aqi
      • now
      • suggestion
      • daily_forecast
      • weather
    • 编写天气界面
    • 将天气信息显示到界面上
    • 点击地区跳转到具体天气信息界面
    • 载入背景图
    • 测试

显示天气信息

解析天气数据

首先,天气信息的形式是JSON,借助GSON来对天气信息进行解析。

数据的大致形式如下:

其中,除了状态status内容为字符串,其他5类中都再包含具体内容,故可以定义5个具体的类来描述他们。

basic

basic中,city表示城市名,id为城市对应的Weather_id,又包含一个update类,所以需要一个update类,里面包含一个字符串loc表示更新时间。按照此结构可以在gson下建立Basic类。

public class Basic  {//由于JSON中的一些字段可能不太适合直接作为Java字段来命名,因此这里使用了//@ SerializedName注解的方式来让JSON字段和Java字段之间建立映射关系@SerializedName("city")public String cityName;@SerializedName("id")public String weatherId;public Update update;public class Update{@SerializedName("loc")public String updateTime;}
}

aqi

其他几个类也类似

AQI表示空气质量

建立AQI类来对应JSON类:

public class AQI {public AQICity city;public class AQICity{public String aqi;public String pm25;}
}

now

now中包含当前温度和一个cond类来包含当前天气类别。

public class Now  {@SerializedName("tmp")public String tmp;@SerializedName("cond")public More More;public class More{@SerializedName("txt")public String info;}
}

suggestion

建议类中包含三个类,comf表示天气体感,cw表示洗车建议,sport表示运动建议

public class Suggestion {@SerializedName("comf")public Comfort comfort;@SerializedName("cw")public CarWash carWash;public Sport sport;public class Sport{@SerializedName("txt")public String info;}public class CarWash{@SerializedName("txt")public String info;}public class Comfort{@SerializedName("txt")public  String info;}
}

daily_forecast

这个类比较特殊,包含未来一周天气信息,由于每天的信息都是相同的,所以只需定义出单日的天气实体类即可,然后在使用时使用集合类封装即可。

/*
可以看到, daily forecast中包含的是一个数组,数组中的每一项都代表着未来一天的天
气信息。针对于这种情况,我们只需要定义出单日天气的实体类就可以了,然后在声明实体类引
用的时候使用集合类型来进行声明。*/
public class Forecast {public String date;@SerializedName("cond")public More more;@SerializedName("tmp")public Temperature Temperature;public class Temperature{public String max;public String min;}public class More{@SerializedName("txt_d")public String info;}
}

weather

还需要一个总的实例类来将上面创建好的类整合起来。

/*
在 Weather类中,我们对 Basic、AQI、NoW、 Suggestion和 Forecast类进行了引用。其
中,由于 daily forecast中包含的是一个数组,因此这里使用了List集合来引用 Forecast类。*/
public class Weather {/*另外,返回的天气数据中还会包含一项 status数据,成功返回ok,失败则会返回具体的原因,那么这里也需要添加一个对应的 status字段现在所有的GSON实体类都定义好了,接下来我们开始编写天气界面。*/public String status;public Basic basic;public AQI aqi;public Now now;public Suggestion suggestion;@SerializedName("daily_forecast")public List<Forecast> mForecastList;
}

其中,由于daily_forecast中包含一个数组,因此使用了List集合来引用Forecast类。

编写天气界面

这部分没什么好总结的,接按照需要编写即可,注意的是由于界面比较复杂,所有可以分开编写xml文件然后汇总在界面中。

activity_weather.xml

<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorPrimary"><ImageViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/bing_pic_img"android:scaleType="centerCrop"/><ScrollViewandroid:id="@+id/weather_layout"android:layout_width="match_parent"android:layout_height="match_parent"android:scrollbars="none"android:overScrollMode="never"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:fitsSystemWindows="true"><include layout="@layout/title"/><include layout="@layout/now"/><include layout="@layout/forecast"/><include layout="@layout/aqi"/><include layout="@layout/suggestion"/></LinearLayout></ScrollView></FrameLayout>

将天气信息显示到界面上

首先需要添加一个工具类用于解析天气JSON数据

ublic static Weather handleWeatherResponse(String response){/*handleWeatherResponse()方法中先是通过jsonObject和jsonArray将天气数据中的主体内容解析出来*/try {JSONObject jsonObject = new JSONObject(response);JSONArray jsonArray = jsonObject.getJSONArray("HeWeather");String weatherContent = jsonArray.getJSONObject(0).toString();return new Gson().fromJson(weatherContent,Weather.class);} catch (JSONException e) {e.printStackTrace();}return null;
}

接下来就是在活动中请求天气数据,解析数据,并将数据显示到界面上。

 protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);View decorView = getWindow().getDecorView();decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);getWindow().setStatusBarColor(Color.TRANSPARENT);setContentView(R.layout.activity_weather);//初始化各控件mWeatherLayout = findViewById(R.id.weather_layout);mTitleCity = findViewById(R.id.title_city);mTitleUpdateTime = findViewById(R.id.title_update_time);mDegreeText = findViewById(R.id.degree_text);mWeatherInfoText = findViewById(R.id.weather_info_text);mForecast = findViewById(R.id.forecast_layout);mAqiText = findViewById(R.id.aqi_text);mPm25Text = findViewById(R.id.pm25_text);mComfortText = findViewById(R.id.comfort_text);mCarWashText = findViewById(R.id.car_wash_text);mSportText = findViewById(R.id.sport_text);bingPicImg = findViewById(R.id.bing_pic_img);
//在 on create()方法中仍然先是去获
//取一些控件的实例,然后会尝试从本地缓存中读取天气数据。那么第一次肯定是没有缓存的,因
//此就会从 Intent中取出天气id,并调用 requestWeather()方法来从服务器请求天气数据。注意,
//请求数据的时候先将 ScrollⅤview进行隐藏,不然空数据的界面看上去会很奇怪。SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);String weatherString = prefs.getString("weather", null);if (weatherString != null){//有缓存直接解析天气数据Weather weather = Utility.handleWeatherResponse(weatherString);showWeatherInfo(weather);}else{//无缓存去服务器查询天气String weatherId = getIntent().getStringExtra("weather_id");mWeatherLayout.setVisibility(View.INVISIBLE);//请求天气requestWeather(weatherId);}String bingPic = prefs.getString("bing_pic", null);if (bingPic!=null){Glide.with(this).load(bingPic).into(bingPicImg);}else {loadBingPic();}}

requestWeather()用来请求具体城市天气信息。先是调用HttpUtil.sendOkHttpRequest传入拼接的Url,Url由api和天气id和申请的个人key组成,之后主要是处理回调中的onResponse。

   /*根据天气Id请求城市天气信息requestWeather()方法中先是使用了参数中传入的天气id和我们之前申请好的 API Key拼装
出一个接地址,接着调用Httputil.endokhttpreQuest()方法来向该地址发出请求,服务器
会将相应城市的天气信息以JSON格式返回。然后我们在 onResponse()回调中先调用 Utility
handleWeatherResponse()方法将返回的JSON数据转换成 Weather对象,再将当前线程切换到
主线程。然后进行判断,如果服务器返回的 status状态是ok并且转后的weather不为空,就说明请求天气成功了,此时将返
回的数据缓存到 SharedPreferences当中,并调用 showweatherinfo()方法来进行内容显示。*/private void requestWeather(final String weatherId) {String weatherUrl = "http://guolin.tech/api/weather?cityid=" + weatherId +"&key=755a053d247341699ebbe941099d994f";HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() {@Overridepublic void onFailure(Call call, IOException e) {runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(WeatherActivity.this, "获取天气信息失败", Toast.LENGTH_SHORT).show();}});}@Overridepublic void onResponse(Call call, Response response) throws IOException {final String responseText = response.body().string();final Weather weather = Utility.handleWeatherResponse(responseText);runOnUiThread(new Runnable() {@Overridepublic void run() {if (weather != null&&"ok".equals(weather.status)){SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();editor.putString("weather",responseText);editor.apply();showWeatherInfo(weather);}else {Toast.makeText(WeatherActivity.this, "获取天气数据失败1", Toast.LENGTH_SHORT).show();}}});}});loadBingPic();}

showWeatherInfo()

   /*showweather Info()方法中的逻辑就比较简单了,其实就是从 Weather对象中获取数据
然后显示到相应的控件上。注意在未来几天天气预报的部分我们使用了一个for循环来处理每天
的天气信息,在循环中动态加载 forecast item.xml布局并设置相应的数据,然后添加到父布局当
中。设置完了所有数据之后,记得要将 Scrollview重新变成可见。
这样我们就将首次进入 WeatherActivity时的逻辑全部梳理完了,那么当下一次再进入
Weather Actiⅳvity时,由于缓存已经存在了,因此会直接解析并显示天气数据,而不会再次发起网
络请求了。*/private void showWeatherInfo(Weather weather) {String cityName = weather.basic.cityName;String updateTime = weather.basic.update.updateTime.split(" ")[1];String degree =  weather.now.tmp+"°C";String weatherInfo = weather.now.More.info;mTitleCity.setText(cityName);mTitleUpdateTime.setText(updateTime);mDegreeText.setText(degree);mWeatherInfoText.setText(weatherInfo);mForecast.removeAllViews();for (Forecast forecast:weather.mForecastList){View view = LayoutInflater.from(this).inflate(R.layout.forecast_item,mForecast,false);TextView dateText = view.findViewById(R.id.date_text);TextView infoText = view.findViewById(R.id.info_text);TextView maxText = view.findViewById(R.id.max_text);TextView minText = view.findViewById(R.id.min_text);dateText.setText(forecast.date);infoText.setText(forecast.more.info);maxText.setText(forecast.Temperature.max);minText.setText(forecast.Temperature.min);mForecast.addView(view);}if (weather.aqi!=null){mAqiText.setText(weather.aqi.city.aqi);mPm25Text.setText(weather.aqi.city.pm25);}String comfort = "舒适度" + weather.suggestion.comfort.info;String carwash = "洗车指数" +weather.suggestion.carWash.info;String sport = "运动建议" + weather.suggestion.sport.info;mComfortText.setText(comfort);mCarWashText.setText(carwash);mSportText.setText(sport);mWeatherLayout.setVisibility(View.VISIBLE);}

点击地区跳转到具体天气信息界面

完善ListView.setOnItemClickListener

/*
列表点击事件*/
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {//可以看到,我们使用 setonItemClicklistener()方法为 Listview注册了一个监听器,当//用户点击了 Listview中的任何一个子项时,就会回调 onItemclick()方法。在这个方法中可以//通过 position参数判断出用户点击的是哪一个子项,然后获取到相应的类信息,并通过Toast显示@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int pos, long idl) {//当你点击了某个item的时候会进入到 List view的 onItemclick()方法中,这个时候会根据当//前的级别来判断是去调用 querycities()方法还是 query Counties()方法, queryCities()方//法是去査询市级数据,而 queryCounties()方法是去查询县级数据,这两个方法内部的流程和//queryProvinces()方法基本相同if (currentLevel == LEVEL_PROVINCE){selectedProvince = provinceList.get(pos);queryCity();}else if (currentLevel == LEVEL_CITY){selectedCity = cityList.get(pos);queryCounty();}else if (currentLevel == LEVEL_COUNTY){//非常简单,这里在 onitemclick()方法中加入了一个if判断,如果当前级别是 LEVEL//COUNTY,就启动 WeatherActivity,并把当前选中县的天气i传递过去。String weatherId = countyList.get(pos).getWeatherId();Intent intent = new Intent(getActivity(),WeatherActivity.class);intent.putExtra("weather_id",weatherId);startActivity(intent);getActivity().finish();}}
});

在MainActivity中加入一个缓存数据判断,在启动程序时若发现已有缓存则跳转到天气页面。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//可以看到,这里在 oncreate()方法的一开始先从 Shared Preferences文件中读取缓存数据//如果不为nulL就说明之前已经请求过天气数据了,那么就没必要让用户再次选择城市,而是直//接跳转到 Weather Activity即可。SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);if (preferences.getString("weather",null)!=null){Intent intent = new Intent(this,WeatherActivity.class);startActivity(intent);finish();}}
}

载入背景图

这里选用的是必应的每日一图进行更新背景,首先在布局中插入图片作为背景。

<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorPrimary"><ImageViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/bing_pic_img"android:scaleType="centerCrop"/><ScrollView...

这里我们在 FrameLayout中添加了一个 Image View,并且将它的宽和高都设置成mach
parent。由于 Framelayout默认情况下会将控件都放置在左上角,因此 Scrollview会完全覆盖住
mage View,从而 ImageView也就成为背景图片了。

接着在WeatherActivity中初始化控件,并且加载请求必应每日一图函数。

        bingPicImg = findViewById(R.id.bing_pic_img);
//先看看有没有图片链接缓存,若没有则请求获取图片链接,若已有则直接加载图片...String bingPic = prefs.getString("bing_pic", null);if (bingPic!=null){Glide.with(this).load(bingPic).into(bingPicImg);}else {loadBingPic();}
/*
loadBingPic()方法中的逻辑就非常简单了,先是调用了Httputil.sendokhttprequest()
方法获取到必应背景图的链接,然后将这个链接缓存到 SharedPreferences当中,再将当前线程切
换到主线程,最后使用 Glide来加载这张图片就可以了。另外需要注意,在 requestweather()
方法的最后也需要调用一下loadBingPic()方法,这样在每次请求天气信息的时候同时也会刷
新背景图片。*/private void loadBingPic() {String requestBingPic = "http://guolin.tech/api/bing_pic";HttpUtil.sendOkHttpRequest(requestBingPic, new Callback() {@Overridepublic void onFailure(Call call, IOException e) {e.printStackTrace();}@Overridepublic void onResponse(Call call, Response response) throws IOException {final String bingPic = response.body().string();SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();editor.putString("bing_pic",bingPic);editor.apply();//切换回主线程runOnUiThread(new Runnable() {@Overridepublic void run() {Glide.with(WeatherActivity.this).load(bingPic).into(bingPicImg);}});}});}

测试

动手实现天气预报App(二)——显示天气信息相关推荐

  1. domoticz添加和风天气,让domoticz显示天气信息

    1.domoticz添加天气信息 domoticz中可以很方便的通过dark sky api显示天气信息,但是dark sky的信息不太准确,想添加国内天气的信息,网上的都是通过彩云的api获取jso ...

  2. 动手实现天气预报App(一)——数据、工具类和碎片布局准备

    文章目录 需求分析 数据来源 创建数据库和表 加载全国省市区数据 请求和解析数据工具类 碎片界面布局 加载数据碎片逻辑 测试 本系列记录一下跟随guolin大神学习的项目自己完成一个天气预报Andro ...

  3. Android看天气预报,Android开源天气预报app - 清新小天气

    #LittleFreshWeather 源码github地址 这是一款简洁的天气预报app--清新小天气,它能够支持国内绝大多数城市,提供包含实时天气.七天预报.实时气象信息及生活指数等预报信息... ...

  4. Android开源天气预报app - 清新小天气

    #LittleFreshWeather 源码github地址 这是一款简洁的天气预报app--清新小天气,它能够支持国内绝大多数城市,提供包含实时天气.七天预报.实时气象信息及生活指数等预报信息... ...

  5. echarts实现-百度山西省热力图-标点显示天气信息

    一.效果图 三维地图数据暂时未加 二.代码 <!DOCTYPE html><html><head><meta http-equiv="Content ...

  6. 用于android天气开发的背景图,Android开发天气预报APP的设计与实现毕业设计.pdf

    摘要 随着移动互联网技术和通信技术的发展,智能手机几乎成为人们 生活的必需品.近年来,Android系统已经成为智能手机中用户量最 多的操作系统.通过Android程序开发和设计天气预报手机应用,可 ...

  7. android app 天气功能,Android天气预报app改进版

    最近总是有人来和我说我以前写的一个小app无法正常获取数据~Android简易版天气预报app 今天就又运行了下来查找问题,发现或许是接口有限制吧,不能在多台手机使用同个apikey 然后,发现了我写 ...

  8. 基于Android开发的天气预报app(源码下载)

    基于AndroidStudio环境开发的天气app 由于需要源码的人特别多,我特地花时间新增了对最新IDE版本Android Studio Chipmunk | 2021.2.1 Patch 1的支持 ...

  9. php定位和天气,基于thinkphp实现依据用户ip判断地理位置并提供对应天气信息的应用...

    基于thinkphp实现根据用户ip判断地理位置并提供对应天气信息的应用 我们都知道,在很多的网站都提供了给用户提供天气预报的功能,有时会发现,用户即使不输入任何和自己有关的地理位置信息,同样的网站也 ...

最新文章

  1. 皮尔逊相关系数 定义+python代码实现 (与王印讨论公式)
  2. Serval and Bus
  3. css中定义超级链接的样式
  4. 计算机二级语义网络的研究现状与展望,计算机二级access选择题题库研究.doc
  5. 【转】jquery 注册事件的方法
  6. (2)打两拍systemverilog与VHDL编码
  7. 计算机 识别u盘 原理,电脑与USB3.0之间的识别过程,识别原理,高额金币悬赏!...
  8. Docker 外部访问容器Pp、数据管理volume、网络network 介绍
  9. 资产管理界的风控大师-贝莱德BlackRock集团
  10. C语言函数的声明、定义、调用
  11. 上海嵌联自控供应车流量统计系统
  12. 自动控制理论——拉普拉斯变换定义及性质
  13. java7 diamond_java7新特性之Diamond syntax
  14. java fadein_原生JS实现 fadeIn / fadeOut 方法
  15. php获得当前时间差,PHP获取当前时间差8小时的问题
  16. #453 原汤话原食:除夕夜请热心市民陪我销毁一下烟花爆竹
  17. domain-transfer reid郑哲东 joint 判别和生成REID
  18. java curl 使用方法_如何在Java中使用这个cURL POST请求?(Spotify API)
  19. OpenAI 宣布将对战 DOTA2 世界冠军 OG,最终决战! 1
  20. User-Agent详解

热门文章

  1. 为什么一些linux基础静态库(如libc.a)里面包含那么多目标文件.o呢? 为什么不将这些.o文件进行提前糅合呢?
  2. 基因家族进化分析之DNA序列批量获取
  3. 如何高效提高倾斜摄影三维模型顶层合并的技术方法分析
  4. 行走在前端路上的一些想法
  5. python模拟登录淘宝直通车_Python实现的淘宝直通车数据抓取(2)
  6. python 文字转换成声音
  7. 《寒江独钓——windows内核安全编程》vs2019+wdk10开发xp驱动
  8. 无人机倾斜摄影测量技术有哪些特点?
  9. APP机型兼容测试的手机选择
  10. PostgreSQL助力小微企业管理系统变革