📌简易的安卓天气app(一)——解析Json数据、数据类封装
简易的安卓天气app(二)——适配器、每小时数据展示
简易的安卓天气app(三)——城市管理、数据库操作
简易的安卓天气app(四)——搜索城市、完善页面

简述

不罗嗦那么多没用的;;;
既然是简易的天气app,那么本demo就没有那麽多复杂的交互,页面跳转,只包括了针对api获取和解析数据放到app主页面,由于配置定位服务太繁琐,本次测试没有使用定位功能。
项目只包含一个主要activity_main.xml,两个封装的实体用来存数据
用到的天气api可前往官网注册账号获取:天气api

例如我这里注册好了我的账号,进入主页面得到下图的appid和appsecret
appid然后把这两个东西复制粘贴到下面的api中

1
2
//里面的括号中的两个参数值换成你的,包括括号
https://tianqiapi.com/api?version=v1&appid=(你的appid)&appsecret=(你的appsecret)

==注意==:
>

慎用此接口,每天有免费使用==上限==(如果你不想充钱)
地址栏搜索默认是当前所在城市,若是指定城市url后面加上&city=城市名,就行

接着,访问此url结果如图,一长串的json数据
json数据如果你的浏览器支持转为json格式,那么会得到更清晰的数据格式,方便后续对其进行封装,也可百度在线json格式化工具,复制原始数据进去,得到格式化jsn数据
json格式1观察上图json数据,里面的嵌套关系决定了我们封装一个实体类肯定不能拿到全部信息,因为上图data,是一个json数组(JsonArray),里面包含了今天加上未来六天共七天的天气数据(JsonObject),所以data要单独封装成一个实体叫做DayWeatherBean,用来接受每天的数据。

项目结构

项目结构

api请求工具包

那么既然是请求api解析数据,自然离不开HttpUrlConnection,如果学的不是HttpUrlConnection请自行根据更改。
首先封装一个工具包,表示根据指定地址网络请求得到数据,得到的是string字符串,实是json数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class NetworkUtil {
// 一天测试次数有限,慎用
public static final String URL_WEATHER = "https://tianqiapi.com/api?version=v1&appid=(你的appid)&appsecret=(你的appsecret)";

public static String getWeather() {
String result = "";
HttpURLConnection connection = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
// 连接网络
try {
URL urL = new URL(URL_WEATHER);
connection = (HttpURLConnection) urL.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
// 从连接中读取数据(二进制)
InputStream inputStream = connection.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
// 二进制流送入缓冲区
bufferedReader = new BufferedReader(inputStreamReader);
// 容器
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line);
}
result = stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
}finally {
if (connection != null) {
connection.disconnect();
}

if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
return result;
}

既然是网络请求,注意
>

AndroidManifest中别忘了加
<uses-permission android:name="android.permission.INTERNET" />

andxml

布局文件

接着就是布局,随意,怎么好看怎么来,无非就是接受几个数据传给TextView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.8"
android:background="@mipmap/bg"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:context=".MainActivity">


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="郑州"
android:textSize="25sp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="@color/white"
android:id="@+id/tv_city"/>

<ImageView
android:id="@+id/iv_weather"
android:layout_width="125dp"
android:layout_height="95dp"
android:src="@drawable/weather_yin" />

<TextView
android:id="@+id/tv_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="阴转多云"
android:textColor="@color/white"
android:textSize="20sp" />

<TextView
android:id="@+id/tv_week"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="星期二"
android:textColor="@color/white"
android:textSize="16sp" />

<TextView
android:id="@+id/tv_tem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="31°C"
android:textColor="@color/white"
android:textSize="100sp" />


<TextView
android:id="@+id/tv_tem_low_high"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="25°C/33°C"
android:textColor="@color/white"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="更新时间:2022-06-15 08:22:23"
android:textColor="@color/white"
android:textSize="17sp" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:alpha="0.7"
android:background="@drawable/blackground"
android:orientation="horizontal"

>

<LinearLayout
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="5dp"
android:gravity="center"
android:orientation="vertical">

<ImageView
android:layout_width="105dp"
android:layout_height="65dp"
android:src="@drawable/fengli" />

<TextView
android:id="@+id/tv_win"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="南风3~4级"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"

android:orientation="horizontal">

<TextView
android:id="@+id/tv_air"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:text="空气:43 | 优\n空气好,适宜外出"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>

</LinearLayout>

</LinearLayout>

效果图(上图有个阴转多云图,下方有源码,可自行了解,此次只拿数据传数据,不包括图片)
效果图

实体类

两个实体类
在这里插入图片描述
一个WeatherBean是最上层json封装,一个是DayWeatherBean封装的data(前面已经解答过)

WeatherBean

没什么好说的,就下面几个属性,学爬虫的应该更了解
在这里插入图片描述
其他的属性String就行,挑重要信息拿,data就是··List<DayWeatherBean>

此处命名不规范问题,由于使用的是Gson包封装,所以有一个实现类可用
public class WeatherBean implements Serializable
每个属性再加上序列化注解指定原始数据,就可解决,自行补充
在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.List;

/**
* TextView tv_city,tv_time,tv_weather,tv_week,tv_tem,tv_tem_low_high,tv_win,tv_air;7个
* ImageView iv_weather;//天气图标
*/
public class WeatherBean {

private String cityid;
private String city;//城市名称
private String update_time;//更新时间
private List<DayWeatherBean> data;//获取今日天气,get[0]

//toString(),get,set自行设置
}

DayWeatherBean

接着根据api中data中的属性名选择性封装DayWeatherBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.Arrays;

/**
* TextView tv_city,tv_time,tv_weather,tv_week,tv_tem,tv_tem_low_high,tv_win,tv_air;7个
* ImageView iv_weather;//天气图标
*/
public class DayWeatherBean {
private String wea;//天气
private String wea_img;//天气图标
private String week;//周几
private String tem;//温度
//tv_tem_low_high=tem2+tem1拼接一起
private String tem2;//低温
private String tem1;//高温
//tv_win=win+win_speed
private String[] win;//风力
private String win_speed;//风力等级
//tv_air=air+air_level+air_tips拼接一起
private String air;//
private String air_level;//
private String air_tips;//

//toString(),get,set自行设置

MainActivity

使用handler来异步处理
首先开辟一个子线程,拿到网页数据传给handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void getWeather() {
// 开启子线程,请求网络
new Thread(new Runnable() {
@Override
public void run() {
// 请求网络
String weatherJson = NetworkUtil.getWeather();
// 使用handler将数据传递给主线程
Message message = Message.obtain();
message.what = 0;
message.obj = weatherJson;
mHandler.sendMessage(message);
}
}).start();

}

使用Gson序列化工具前别忘记添加依赖包
implementation 'com.google.code.gson:gson:2.8.5'
在这里插入图片描述
添加代码后别忘了构建一下,右上角点一下
在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private Handler mHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
String weather = (String) msg.obj;
Log.d("Main", ">>>>>>原始数据--weather---" + weather);
if (TextUtils.isEmpty(weather)) {
Toast.makeText(MainActivity.this, "天气数据为空!", Toast.LENGTH_LONG).show();
return;
}
Gson gson = new Gson();//Gson序列化工具,JsonObject也行,方法不同
WeatherBean weatherBean = gson.fromJson(weather, WeatherBean.class);
if (weatherBean != null) {
Log.d("Main", ">>>>>>封装数据--weather---" + weatherBean.toString());
}

tvCity.setText(weatherBean.getCity());
tvTime.setText(weatherBean.getUpdate_time());
/**
* 当天天气
*/
dayWeather = weatherBean.getData().get(0);
tvWeather.setText(dayWeather.getWea());
tvTem.setText(dayWeather.getTem());
tvTemLowHigh.setText(dayWeather.getTem2()+"/"+dayWeather.getTem1());
tvWeek.setText(dayWeather.getWeek());
tvWin.setText(dayWeather.getWin()[0]+dayWeather.getWin_speed());
tvAir.setText("空气:"+dayWeather.getAir()+" | "+dayWeather.getAir_level()+"\n"+dayWeather.getAir_tips());
ivWeather.setImageResource(WeatherImgUtil.getImgResOfWeather(dayWeather.getWea_img()));
//此工具和图片源码中给出
}
}
};

查看是否获取到数据
在这里插入图片描述

==源码自取==:gitee