Android开发实战-项目学习笔记(2)
获取市信息
代码部分:
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.ListView;import com.example.jnsyq.data.Sheng;import com.example.jnsyq.data.Shi;import com.example.jnsyq.data.Xian;import org.jetbrains.annotations.NotNull;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.IOException;import java.util.ArrayList;import java.util.List;import okhttp3.Call;import okhttp3.Callback;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;public class MainActivity extends AppCompatActivity { //定义3个级别 private static final int level_sheng = 0; private static final int level_shi = 1; private static final int level_xian = 2; private int level = 0; //变化 //声明ListView private ListView listView; //声明省市县对应的列表 private List<Sheng> ShengList = new ArrayList<>(); private List<Shi> ShiList = new ArrayList<>(); private List<Xian> XianList = new ArrayList<>(); //声明省市县名称列表:数据源 private List<String> nameList = new ArrayList<>(); //创建适配器 private ArrayAdapter<String> adapter; //全局的选中的省市县城市 private Sheng s; private Shi shi; //消息处理 //【内存泄漏】 Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //通知ListView数据更改 adapter.notifyDataSetChanged(); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //调用初始化方法 initListView(); //联网初始化省信息 getSheng(); } /** * 新建初始化ListView方法 */ private void initListView() { //初始化ListView //在布局文件中找到该ListView listView = (ListView) findViewById(R.id.listview); //数据源、ListView、适配器实现绑定,数据和显示实时更新 //初始化适配器,将适配器和数据源绑定在一起 //this:上下文 //simple_list_item_1:简单的布局 //nameList:设置数据源 adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, nameList); //绑定ListView和适配器,ListView设置适配器 listView.setAdapter(adapter); //设置点击操作 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //通过点击的位置获取到点击的对象 //如果当前级别是省级,那么获取省级对象,获取市级对象 if (level == level_sheng) { level = 1; s = ShengList.get(position); Log.d("MainActivity", "onItemClick: " + s.getName()); getShi(); } else if (level == level_shi) { shi = ShiList.get(position); Log.d("MainActivity", "onItemClick: " + shi.getName()); } } }); } /** * 获取省一级的城市列表 */ private void getSheng() { //定义url,接口 String url = "http://guolin.tech/api/china"; //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 //new Callback():回调接口(线程) client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) {// e.printStackTrace(); //如果访问失败,输出失败信息 Log.d("MainActivity", "onFailure: 网络访问失败"); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //将网络相应信息转换成字符串型 //该操作只能执行一次 String data = response.body().string();// String data1 = response.body().string(); //错误 //输出日志信息 Log.d("MainActivity", "onResponse: " + data); //解析数据,并生成数据类 try { //将json字符串转换为json数组 JSONArray shengs = new JSONArray(data); //需处理JSONException,未处理异常【用try/catch包括起来】 //遍历json数字,读取所有的json对象 for (int i = 0; i < shengs.length(); i++) { //从json数组中读取json对象 JSONObject shengObject = shengs.getJSONObject(i); //创建省一级城市对象 Sheng s = new Sheng(); //设置对应的值 s.setId(shengObject.getInt("id")); s.setName(shengObject.getString("name")); //将省对象添加到列表中 ShengList.add(s); //将省名称添加到名称列表 nameList.add(s.getName()); //发送消息到Loop //通过handleMessage进行消息处理 Message msg = new Message(); msg.what = 0; //消息id号 handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取市级的城市列表 * 法1:方法中缺少变量,可以直接传递进来 */// private void getShi(int shengid) {// //url中省级id号是变量,url不完整// String url = "http://guolin.tech/api/china/" + shengid;// } /** * 获取市级的城市列表 * 法2:①将被选中的省级城市定义为全部变量 * ②在getShi方法中进行读取 */ private void getShi() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId(); //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Shi shi = new Shi(); shi.setId(jsonObject.getInt("id")); shi.setName(jsonObject.getString("name")); ShiList.add(shi); nameList.add(shi.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); }}
效果图:
获取省级信息
代码部分:
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.ListView;import com.example.jnsyq.data.Sheng;import com.example.jnsyq.data.Shi;import com.example.jnsyq.data.Xian;import org.jetbrains.annotations.NotNull;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.IOException;import java.util.ArrayList;import java.util.List;import okhttp3.Call;import okhttp3.Callback;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;public class MainActivity extends AppCompatActivity { //定义3个级别 private static final int level_sheng = 0; private static final int level_shi = 1; private static final int level_xian = 2; private int level = 0; //变化 //声明ListView private ListView listView; //声明省市县对应的列表 private List<Sheng> ShengList = new ArrayList<>(); private List<Shi> ShiList = new ArrayList<>(); private List<Xian> XianList = new ArrayList<>(); //声明省市县名称列表:数据源 private List<String> nameList = new ArrayList<>(); //创建适配器 private ArrayAdapter<String> adapter; //全局的选中的省市县城市 private Sheng s; private Shi shi; private Xian xian; //消息处理 //【内存泄漏】 Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //通知ListView数据更改 adapter.notifyDataSetChanged(); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //调用初始化方法 initListView(); //联网初始化省信息 getSheng(); } /** * 新建初始化ListView方法 */ private void initListView() { //初始化ListView //在布局文件中找到该ListView listView = (ListView) findViewById(R.id.listview); //数据源、ListView、适配器实现绑定,数据和显示实时更新 //初始化适配器,将适配器和数据源绑定在一起 //this:上下文 //simple_list_item_1:简单的布局 //nameList:设置数据源 adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, nameList); //绑定ListView和适配器,ListView设置适配器 listView.setAdapter(adapter); //设置点击操作 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //通过点击的位置获取到点击的对象 //如果当前级别是省级,那么获取省级对象,获取市级对象 if (level == level_sheng) { level = level_shi; s = ShengList.get(position); Log.d("MainActivity", "onItemClick: " + s.getName()); getShi(); } else if (level == level_shi) { level = level_xian; shi = ShiList.get(position); Log.d("MainActivity", "onItemClick: " + shi.getName()); getXian(); } else if (level == level_xian) { xian = XianList.get(position); Log.d("MainActivity", "onItemClick: " + xian.getName()); } } }); } /** * 获取省一级的城市列表 */ private void getSheng() { //定义url,接口 String url = "http://guolin.tech/api/china"; //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 //new Callback():回调接口(线程) client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) {// e.printStackTrace(); //如果访问失败,输出失败信息 Log.d("MainActivity", "onFailure: 网络访问失败"); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //将网络相应信息转换成字符串型 //该操作只能执行一次 String data = response.body().string();// String data1 = response.body().string(); //错误 //输出日志信息 Log.d("MainActivity", "onResponse: " + data); //解析数据,并生成数据类 try { //将json字符串转换为json数组 JSONArray shengs = new JSONArray(data); //需处理JSONException,未处理异常【用try/catch包括起来】 //遍历json数字,读取所有的json对象 for (int i = 0; i < shengs.length(); i++) { //从json数组中读取json对象 JSONObject shengObject = shengs.getJSONObject(i); //创建省一级城市对象 Sheng s = new Sheng(); //设置对应的值 s.setId(shengObject.getInt("id")); s.setName(shengObject.getString("name")); //将省对象添加到列表中 ShengList.add(s); //将省名称添加到名称列表 nameList.add(s.getName()); //发送消息到Loop //通过handleMessage进行消息处理 Message msg = new Message(); msg.what = 0; //消息id号 handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取市级的城市列表 * 法1:方法中缺少变量,可以直接传递进来 */// private void getShi(int shengid) {// //url中省级id号是变量,url不完整// String url = "http://guolin.tech/api/china/" + shengid;// } /** * 获取市级的城市列表 * 法2:①将被选中的省级城市定义为全部变量 * ②在getShi方法中进行读取 */ private void getShi() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId(); //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Shi shi = new Shi(); shi.setId(jsonObject.getInt("id")); shi.setName(jsonObject.getString("name")); ShiList.add(shi); nameList.add(shi.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取县级的城市列表 */ private void getXian() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId() + "/" + shi.getId(); //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Xian xian = new Xian(); xian.setId(jsonObject.getInt("id")); xian.setName(jsonObject.getString("name")); xian.setWeather_id(jsonObject.getString("weather_id")); XianList.add(xian); nameList.add(xian.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); }}
效果图:
省市县返回问题
选错了省市县以后退回上一级别选择
注:通过重写actionbar实现返回的功能
第一步:
在res/values
中,修改styles.xml
代码,效果如下:
第二步:
在res/drawable
中图片,插入修改xml
ic_back.png
ic_home.png
<?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:orientation="vertical" tools:context=".MainActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary"> <Button android:id="@+id/back" android:layout_width="32dp" android:layout_height="32dp" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:layout_marginLeft="10dp" android:layout_marginStart="10dp" android:background="@drawable/ic_back" android:layout_alignParentStart="true" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="20sp" android:textColor="#fff" tools:text="山东"/> RelativeLayout> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/>LinearLayout>
- layout_centerVertical:上下居中,垂直居中
- layout_alignParentLeft:左边,居左
- layout_alignParentStart:开始,根据设置不同读取文字方向,其作用不同
- 从左向右,start代表左边
- 从右往左,start代表右边
- layout_marginLeft:左边间隔
- layout_marginStart:开始间隔
- layout_centerInParent:在父组件布局中居中
- tools:占位,程序运行时不会显示出来
效果图:
第三步:
声明控件
标题自定义
主要代码,截图:
Button返回
主要代码,截图:
问题:
网络访问
省级 -> 市级 -> 网络访问 需要
市级 -> 省级 -> 网络访问 不需要
修改代码,截图:
注:清空
反复重写
MainActivity.java中网络访问省市县三步走相同,故可以提取出来,新建工具类,方法调用
修改前:
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import com.example.jnsyq.data.Sheng;import com.example.jnsyq.data.Shi;import com.example.jnsyq.data.Xian;import org.jetbrains.annotations.NotNull;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.IOException;import java.util.ArrayList;import java.util.List;import okhttp3.Call;import okhttp3.Callback;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;public class MainActivity extends AppCompatActivity { //定义3个级别 private static final int level_sheng = 0; private static final int level_shi = 1; private static final int level_xian = 2; private int level = 0; //变化 //声明控件 private ListView listView; //ListView private Button buttonBack; //Button private TextView title; //TextView //声明省市县对应的列表 private List<Sheng> ShengList = new ArrayList<>(); private List<Shi> ShiList = new ArrayList<>(); private List<Xian> XianList = new ArrayList<>(); //声明省市县名称列表:数据源 private List<String> nameList = new ArrayList<>(); //创建适配器 private ArrayAdapter<String> adapter; //全局的选中的省市县城市 private Sheng s; private Shi shi; private Xian xian; //消息处理 //【内存泄漏】 Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //通知ListView数据更改 adapter.notifyDataSetChanged(); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonBack = findViewById(R.id.back); //button添加点击操作 buttonBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //点击操作,首先判断当前级别 //如果当前处于县级,返回市级 if (level == level_xian) { level = level_shi; //显示上一级省名称 title.setText(s.getName()); //法1:重新获取一次市级列表// getShi(); //法2:直接遍历市级列表 //将所有的市级名称填到homelist中 nameList.clear(); //ShiList.for回车,自动出 for (Shi shi1 : ShiList) { nameList.add(shi1.getName()); adapter.notifyDataSetChanged(); } } else if (level == level_shi) { level = level_sheng; title.setText("中国"); for (Sheng sheng1 : ShengList) { nameList.add(sheng1.getName()); adapter.notifyDataSetChanged(); } } } }); title = findViewById(R.id.title); title.setText("中国"); //调用初始化方法 initListView(); //联网初始化省信息 getSheng(); } /** * 新建初始化ListView方法 */ private void initListView() { //初始化ListView //在布局文件中找到该ListView listView = (ListView) findViewById(R.id.listview); //数据源、ListView、适配器实现绑定,数据和显示实时更新 //初始化适配器,将适配器和数据源绑定在一起 //this:上下文 //simple_list_item_1:简单的布局 //nameList:设置数据源 adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, nameList); //绑定ListView和适配器,ListView设置适配器 listView.setAdapter(adapter); //设置点击操作 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //通过点击的位置获取到点击的对象 //如果当前级别是省级,那么获取省级对象,获取市级对象 if (level == level_sheng) { level = level_shi; s = ShengList.get(position); //点击的哪个省,那么title显示该省名称 title.setText(s.getName()); Log.d("MainActivity", "onItemClick: " + s.getName()); getShi(); } else if (level == level_shi) { level = level_xian; shi = ShiList.get(position); //点击的哪个市,那么title显示该市名称 title.setText(shi.getName()); Log.d("MainActivity", "onItemClick: " + shi.getName()); getXian(); } else if (level == level_xian) { xian = XianList.get(position); Log.d("MainActivity", "onItemClick: " + xian.getName()); } } }); } /** * 获取省一级的城市列表 */ private void getSheng() { //定义url,接口 String url = "http://guolin.tech/api/china"; //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 //new Callback():回调接口(线程) client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) {// e.printStackTrace(); //如果访问失败,输出失败信息 Log.d("MainActivity", "onFailure: 网络访问失败"); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //将网络相应信息转换成字符串型 //该操作只能执行一次 String data = response.body().string();// String data1 = response.body().string(); //错误 //输出日志信息 Log.d("MainActivity", "onResponse: " + data); //解析数据,并生成数据类 try { nameList.clear(); ShengList.clear(); //将json字符串转换为json数组 JSONArray shengs = new JSONArray(data); //需处理JSONException,未处理异常【用try/catch包括起来】 //遍历json数字,读取所有的json对象 for (int i = 0; i < shengs.length(); i++) { //从json数组中读取json对象 JSONObject shengObject = shengs.getJSONObject(i); //创建省一级城市对象 Sheng s = new Sheng(); //设置对应的值 s.setId(shengObject.getInt("id")); s.setName(shengObject.getString("name")); //将省对象添加到列表中 ShengList.add(s); //将省名称添加到名称列表 nameList.add(s.getName()); //发送消息到Loop //通过handleMessage进行消息处理 Message msg = new Message(); msg.what = 0; //消息id号 handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取市级的城市列表 * 法1:方法中缺少变量,可以直接传递进来 */// private void getShi(int shengid) {// //url中省级id号是变量,url不完整// String url = "http://guolin.tech/api/china/" + shengid;// } /** * 获取市级的城市列表 * 法2:①将被选中的省级城市定义为全部变量 * ②在getShi方法中进行读取 */ private void getShi() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId(); //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); ShiList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Shi shi = new Shi(); shi.setId(jsonObject.getInt("id")); shi.setName(jsonObject.getString("name")); ShiList.add(shi); nameList.add(shi.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取县级的城市列表 */ private void getXian() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId() + "/" + shi.getId(); //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,构建请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); XianList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Xian xian = new Xian(); xian.setId(jsonObject.getInt("id")); xian.setName(jsonObject.getString("name")); xian.setWeather_id(jsonObject.getString("weather_id")); XianList.add(xian); nameList.add(xian.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); }}
修改后:
新建Uitils
工具类,截图和代码部分如下:
import okhttp3.OkHttpClient;import okhttp3.Request;/** * 工具类 */public class HttpUtils { /** * 网络访问三步走 * #注意:static 静态方法,只和类有关系,和对象无关 * @param url 要访问的网络地址 * @param callback 回调 */ public static void sendOkhttpRequest(String url, okhttp3.Callback callback) { //1.创建okhttp客户端 OkHttpClient client = new OkHttpClient(); //2.创建请求,拼接请求参数 Request request = new Request.Builder().url(url).build(); //3.进行网络访问 //new Callback():回调接口(线程) client.newCall(request).enqueue(callback); }}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import com.example.jnsyq.data.Sheng;import com.example.jnsyq.data.Shi;import com.example.jnsyq.data.Xian;import com.example.jnsyq.utils.HttpUtils;import org.jetbrains.annotations.NotNull;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.IOException;import java.util.ArrayList;import java.util.List;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;public class MainActivity extends AppCompatActivity { //定义3个级别 /* static:静态;final:常量 */ private static final int level_sheng = 0; private static final int level_shi = 1; private static final int level_xian = 2; private int level = 0; //变化 //声明控件 private ListView listView; //ListView private Button buttonBack; //Button private TextView title; //TextView //声明省市县对应的列表 private List<Sheng> ShengList = new ArrayList<>(); private List<Shi> ShiList = new ArrayList<>(); private List<Xian> XianList = new ArrayList<>(); //声明省市县名称列表:数据源 private List<String> nameList = new ArrayList<>(); //创建适配器 private ArrayAdapter<String> adapter; //全局的选中的省市县城市 private Sheng s; private Shi shi; private Xian xian; //消息处理loop //【内存泄漏】 Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //通知ListView数据更改 adapter.notifyDataSetChanged(); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonBack = findViewById(R.id.back); //button添加点击操作 buttonBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //点击操作,首先判断当前级别 //如果当前处于县级,返回市级 if (level == level_xian) { level = level_shi; //显示上一级省名称 title.setText(s.getName()); //法1:重新获取一次市级列表// getShi(); //法2:直接遍历市级列表 //将所有的市级名称填到homelist中 nameList.clear(); //ShiList.for回车,自动出 for (Shi shi1 : ShiList) { nameList.add(shi1.getName()); adapter.notifyDataSetChanged(); } } else if (level == level_shi) { level = level_sheng; title.setText("中国"); nameList.clear(); for (Sheng sheng1 : ShengList) { nameList.add(sheng1.getName()); adapter.notifyDataSetChanged(); } } } }); title = findViewById(R.id.title); title.setText("中国"); //调用初始化方法 initListView(); //联网初始化省信息 getSheng(); } /** * 新建初始化ListView方法 */ private void initListView() { //初始化ListView //在布局文件中找到该ListView listView = (ListView) findViewById(R.id.listview); //数据源、ListView、适配器实现绑定,数据和显示实时更新 //初始化适配器,将适配器和数据源绑定在一起 //this:上下文 //simple_list_item_1:简单的布局 //nameList:设置数据源 adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, nameList); //绑定ListView和适配器,ListView设置适配器 listView.setAdapter(adapter); //设置点击操作 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //通过点击的位置获取到点击的对象 //如果当前级别是省级,那么获取省级对象,获取市级对象 if (level == level_sheng) { level = level_shi; s = ShengList.get(position); //点击的哪个省,那么title显示该省名称 title.setText(s.getName()); Log.d("MainActivity", "onItemClick: " + s.getName()); getShi(); } else if (level == level_shi) { level = level_xian; shi = ShiList.get(position); //点击的哪个市,那么title显示该市名称 title.setText(shi.getName()); Log.d("MainActivity", "onItemClick: " + shi.getName()); getXian(); } else if (level == level_xian) { xian = XianList.get(position); Log.d("MainActivity", "onItemClick: " + xian.getName()); //TODO:跳转到天气显示界面 } } }); } /** * 获取省一级的城市列表 */ private void getSheng() { //定义url,接口 String url = "http://guolin.tech/api/china"; //#注意:正常情况下,先创建对象,再调用方法// HttpUtil httpUtil = new HttpUtils();// httpUtil.sendOkhttpRequest(); //每次网络访问时,直接调用sendOkhttpRequest即可 HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) {// e.printStackTrace(); //如果访问失败,输出失败信息 Log.d("MainActivity", "onFailure: 网络访问失败"); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //将网络相应信息转换成字符串型 //该操作只能执行一次 String data = response.body().string();// String data1 = response.body().string(); //错误 //输出日志信息 Log.d("MainActivity", "onResponse: " + data); //解析数据,并生成数据类 try { nameList.clear(); ShengList.clear(); //将json字符串转换为json数组 JSONArray shengs = new JSONArray(data); //需处理JSONException,未处理异常【用try/catch包括起来】 //遍历json数字,读取所有的json对象 for (int i = 0; i < shengs.length(); i++) { //从json数组中读取json对象 JSONObject shengObject = shengs.getJSONObject(i); //创建省一级城市对象 Sheng s = new Sheng(); //设置对应的值 s.setId(shengObject.getInt("id")); s.setName(shengObject.getString("name")); //将省对象添加到列表中 ShengList.add(s); //将省名称添加到名称列表 nameList.add(s.getName()); //发送消息到Loop //通过handleMessage进行消息处理 Message msg = new Message(); msg.what = 0; //消息id号 handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取市级的城市列表 * 法1:方法中缺少变量,可以直接传递进来 */// private void getShi(int shengid) {// //url中省级id号是变量,url不完整// String url = "http://guolin.tech/api/china/" + shengid;// } /** * 获取市级的城市列表 * 法2:①将被选中的省级城市定义为全部变量 * ②在getShi方法中进行读取 */ private void getShi() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId(); HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); ShiList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Shi shi = new Shi(); shi.setId(jsonObject.getInt("id")); shi.setName(jsonObject.getString("name")); ShiList.add(shi); nameList.add(shi.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取县级的城市列表 */ private void getXian() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId() + "/" + shi.getId(); HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); XianList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Xian xian = new Xian(); xian.setId(jsonObject.getInt("id")); xian.setName(jsonObject.getString("name")); xian.setWeather_id(jsonObject.getString("weather_id")); XianList.add(xian); nameList.add(xian.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); }}
其中,TODO表示对未完成情况做标记
效果图:
省级:
市级:
县级:
控制台
显示地名和时间
第一步:
api:http://guolin.tech/api/weather?cityid=CN101190401
创建数据类:使用gsonformat创建实时天气的数据类
- 右键单击,选择
Generate...
- 选择
GsonFormat
效果图如下:
https://www.tianqiapi.com/api?version=v6&appid=55233412&appsecret=2Mm5xcPA&cityid=CN101121101
,复制该网址数据,点击Format
效果图如下:
- 效果如图,点击
OK
代码部分:
package com.example.jnsyq.data;/** * 实时天气数据类 */public class inTimeWeather { /** * cityid : 101250101 * date : 2020-08-14 * week : 星期五 * update_time : 2020-08-14 19:23:53 * city : 长沙 * cityEn : changsha * country : 中国 * countryEn : China * wea : 晴 * wea_img : qing * tem : 33 * tem1 : 34 * tem2 : 27 * win : 南风 * win_speed : 2级 * win_meter : 小于12km/h * humidity : 54% * visibility : 35km * pressure : 1000 * air : 30 * air_pm25 : 30 * air_level : 优 * air_tips : 空气很好,可以外出活动,呼吸新鲜空气,拥抱大自然! * alarm : {"alarm_type":"","alarm_level":"","alarm_content":""} */ private String cityid; private String date; private String week; private String update_time; private String city; private String cityEn; private String country; private String countryEn; private String wea; private String wea_img; private String tem; private String tem1; private String tem2; private String win; private String win_speed; private String win_meter; private String humidity; private String visibility; private String pressure; private String air; private String air_pm25; private String air_level; private String air_tips; private AlarmBean alarm; public String getCityid() { return cityid; } public void setCityid(String cityid) { this.cityid = cityid; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getWeek() { return week; } public void setWeek(String week) { this.week = week; } public String getUpdate_time() { return update_time; } public void setUpdate_time(String update_time) { this.update_time = update_time; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCityEn() { return cityEn; } public void setCityEn(String cityEn) { this.cityEn = cityEn; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCountryEn() { return countryEn; } public void setCountryEn(String countryEn) { this.countryEn = countryEn; } public String getWea() { return wea; } public void setWea(String wea) { this.wea = wea; } public String getWea_img() { return wea_img; } public void setWea_img(String wea_img) { this.wea_img = wea_img; } public String getTem() { return tem; } public void setTem(String tem) { this.tem = tem; } public String getTem1() { return tem1; } public void setTem1(String tem1) { this.tem1 = tem1; } public String getTem2() { return tem2; } public void setTem2(String tem2) { this.tem2 = tem2; } public String getWin() { return win; } public void setWin(String win) { this.win = win; } public String getWin_speed() { return win_speed; } public void setWin_speed(String win_speed) { this.win_speed = win_speed; } public String getWin_meter() { return win_meter; } public void setWin_meter(String win_meter) { this.win_meter = win_meter; } public String getHumidity() { return humidity; } public void setHumidity(String humidity) { this.humidity = humidity; } public String getVisibility() { return visibility; } public void setVisibility(String visibility) { this.visibility = visibility; } public String getPressure() { return pressure; } public void setPressure(String pressure) { this.pressure = pressure; } public String getAir() { return air; } public void setAir(String air) { this.air = air; } public String getAir_pm25() { return air_pm25; } public void setAir_pm25(String air_pm25) { this.air_pm25 = air_pm25; } public String getAir_level() { return air_level; } public void setAir_level(String air_level) { this.air_level = air_level; } public String getAir_tips() { return air_tips; } public void setAir_tips(String air_tips) { this.air_tips = air_tips; } public AlarmBean getAlarm() { return alarm; } public void setAlarm(AlarmBean alarm) { this.alarm = alarm; } public static class AlarmBean { /** * alarm_type : * alarm_level : * alarm_content : */ private String alarm_type; private String alarm_level; private String alarm_content; public String getAlarm_type() { return alarm_type; } public void setAlarm_type(String alarm_type) { this.alarm_type = alarm_type; } public String getAlarm_level() { return alarm_level; } public void setAlarm_level(String alarm_level) { this.alarm_level = alarm_level; } public String getAlarm_content() { return alarm_content; } public void setAlarm_content(String alarm_content) { this.alarm_content = alarm_content; } } }
注:{}表示json对象(Object)对应java里面的类,当使用AlarmBean的时候,set和get给的是AlarmBean
第二步:
创建天气显示Activity
new Empty Activity
,修改名称,效果如下:
MainActivity.java中添加代码,如下:
第三步:
添加gson包,在build.gradle
中添加代码,如下:
implementation "com.google.code.gson:gson:2.8.6"
注意:点击Sync Now
在WeatherActivity.java中,使用gson获取数据,代码如下:
第四步:
activity_weather.xml
<?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:orientation="vertical" tools:context=".WeatherActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary"> <TextView android:id="@+id/title_city" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="20sp" android:textColor="#fff" tools:text="济南"/> <TextView android:id="@+id/title_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:textSize="16sp" android:textColor="#fff" android:layout_marginRight="12dp" android:layout_marginEnd="12dp" tools:text="15:00" /> RelativeLayout>LinearLayout>
注意:textSize设置大小时,尽量使用4的倍数
效果图:
第四步:
完善MainActivity.java【修改省级中变量的名称,jsonArray】和WeatherActivity.java,启动WeatherAcitivity的方法有两种
法1:
MainActivity.java
WeatherActivity.java
法2:
注意:该方法的作用为避免传输数据类型排错
MainActivity.java
WeatherActivity.java
问题:
NullPointerException
变量被声明,没有初始化,内存中不存在被调用导致空指针异常
代码部分:
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.content.SharedPreferences;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import com.example.jnsyq.data.Sheng;import com.example.jnsyq.data.Shi;import com.example.jnsyq.data.Xian;import com.example.jnsyq.utils.HttpUtils;import org.jetbrains.annotations.NotNull;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.IOException;import java.util.ArrayList;import java.util.List;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;public class MainActivity extends AppCompatActivity { //定义3个级别 /* static:静态;final:常量 */ private static final int level_sheng = 0; private static final int level_shi = 1; private static final int level_xian = 2; private int level = 0; //变化 //声明控件 private ListView listView; //ListView private Button buttonBack; //Button private TextView title; //TextView //声明省市县对应的列表 private List<Sheng> ShengList = new ArrayList<>(); private List<Shi> ShiList = new ArrayList<>(); private List<Xian> XianList = new ArrayList<>(); //声明省市县名称列表:数据源 private List<String> nameList = new ArrayList<>(); //创建适配器 private ArrayAdapter<String> adapter; //全局的选中的省市县城市 private Sheng s; private Shi shi; private Xian xian; //消息处理loop //【内存泄漏】 Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //通知ListView数据更改 adapter.notifyDataSetChanged(); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonBack = findViewById(R.id.back); //button添加点击操作 buttonBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //点击操作,首先判断当前级别 //如果当前处于县级,返回市级 if (level == level_xian) { level = level_shi; //显示上一级省名称 title.setText(s.getName()); //法1:重新获取一次市级列表// getShi(); //法2:直接遍历市级列表 //将所有的市级名称填到homelist中 nameList.clear(); //ShiList.for回车,自动出 for (Shi shi1 : ShiList) { nameList.add(shi1.getName()); adapter.notifyDataSetChanged(); } } else if (level == level_shi) { level = level_sheng; title.setText("中国"); nameList.clear(); for (Sheng sheng1 : ShengList) { nameList.add(sheng1.getName()); adapter.notifyDataSetChanged(); } } } }); title = findViewById(R.id.title); title.setText("中国"); //调用初始化方法 initListView(); //联网初始化省信息 getSheng(); } /** * 新建初始化ListView方法 */ private void initListView() { //初始化ListView //在布局文件中找到该ListView listView = (ListView) findViewById(R.id.listview); //数据源、ListView、适配器实现绑定,数据和显示实时更新 //初始化适配器,将适配器和数据源绑定在一起 //this:上下文 //simple_list_item_1:简单的布局 //nameList:设置数据源 adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, nameList); //绑定ListView和适配器,ListView设置适配器 listView.setAdapter(adapter); //设置点击操作 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //通过点击的位置获取到点击的对象 //如果当前级别是省级,那么获取省级对象,获取市级对象 if (level == level_sheng) { level = level_shi; s = ShengList.get(position); //点击的哪个省,那么title显示该省名称 title.setText(s.getName()); Log.d("MainActivity", "onItemClick: " + s.getName()); getShi(); } else if (level == level_shi) { level = level_xian; shi = ShiList.get(position); //点击的哪个市,那么title显示该市名称 title.setText(shi.getName()); Log.d("MainActivity", "onItemClick: " + shi.getName()); getXian(); } else if (level == level_xian) { xian = XianList.get(position); Log.d("MainActivity", "onItemClick: " + xian.getName()); //跳转到天气显示界面 //法1:// Intent intent = new Intent(MainActivity.this, WeatherActivity.class);// //传递cityid到下一个活动// //将weatherid传递到下一个活动,作为cityid参数// intent.putExtra("cityid", xian.getWeather_id());// startActivity(intent); //法2:启动活动的方法 WeatherActivity.actionStart(MainActivity.this, xian.getWeather_id()); } } }); } /** * 获取省一级的城市列表 */ private void getSheng() { //定义url,接口 String url = "http://guolin.tech/api/china"; //#注意:正常情况下,先创建对象,再调用方法// HttpUtil httpUtil = new HttpUtils();// httpUtil.sendOkhttpRequest(); //每次网络访问时,直接调用sendOkhttpRequest即可 HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) {// e.printStackTrace(); //如果访问失败,输出失败信息 Log.d("MainActivity", "onFailure: 网络访问失败"); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //将网络相应信息转换成字符串型 //该操作只能执行一次 String data = response.body().string();// String data1 = response.body().string(); //错误 //输出日志信息 Log.d("MainActivity", "onResponse: " + data); //解析数据,并生成数据类 try { nameList.clear(); ShengList.clear(); //将json字符串转换为json数组 JSONArray jsonArray = new JSONArray(data); //需处理JSONException,未处理异常【用try/catch包括起来】 //遍历json数字,读取所有的json对象 for (int i = 0; i < jsonArray.length(); i++) { //从json数组中读取json对象 JSONObject shengObject = jsonArray.getJSONObject(i); //创建省一级城市对象 Sheng s = new Sheng(); //设置对应的值 s.setId(shengObject.getInt("id")); s.setName(shengObject.getString("name")); //将省对象添加到列表中 ShengList.add(s); //将省名称添加到名称列表 nameList.add(s.getName()); //发送消息到Loop //通过handleMessage进行消息处理 Message msg = new Message(); msg.what = 0; //消息id号 handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取市级的城市列表 * 法1:方法中缺少变量,可以直接传递进来 */// private void getShi(int shengid) {// //url中省级id号是变量,url不完整// String url = "http://guolin.tech/api/china/" + shengid;// } /** * 获取市级的城市列表 * 法2:①将被选中的省级城市定义为全部变量 * ②在getShi方法中进行读取 */ private void getShi() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId(); HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); ShiList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Shi shi = new Shi(); shi.setId(jsonObject.getInt("id")); shi.setName(jsonObject.getString("name")); ShiList.add(shi); nameList.add(shi.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取县级的城市列表 */ private void getXian() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId() + "/" + shi.getId(); HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); XianList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Xian xian = new Xian(); xian.setId(jsonObject.getInt("id")); xian.setName(jsonObject.getString("name")); xian.setWeather_id(jsonObject.getString("weather_id")); XianList.add(xian); nameList.add(xian.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); }}
WeatherActivity.java
import androidx.appcompat.app.AppCompatActivity;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.widget.TextView;import com.example.jnsyq.data.InTimeWeather;import com.example.jnsyq.utils.HttpUtils;import com.google.gson.Gson;import org.jetbrains.annotations.NotNull;import java.io.IOException;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;public class WeatherActivity extends AppCompatActivity { private InTimeWeather inTimeWeather; //声明控件 private TextView titleCity; private TextView titleTime; private String cityid; //private protected public(默认:protected) Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //调用更新ui方法 updateUi(); break; default: break; } } }; public static void actionStart(Context context, String cityid) { Intent intent = new Intent(context, WeatherActivity.class); intent.putExtra("cityid", cityid); context.startActivity(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weather); //从布局中找到控件 titleCity = findViewById(R.id.title_city); titleTime = findViewById(R.id.title_time); //获取意图 Intent intent = getIntent(); //获取上一个活动传递劲来的数据 //初始化cityid的值 cityid = intent.getStringExtra("cityid"); //调用该方法获取数据 getWeatherInfo(); } private void updateUi() { //设置对应值 titleCity.setText(inTimeWeather.getCity()); titleTime.setText(inTimeWeather.getUpdate_time().split(" ")[1]); } /** * 创建获取天气信息的方法 */ private void getWeatherInfo() { //通过调用api获取天气信息 //直接通过ip地址进行天气信息获取 //cityid:变量,由上一个活动传递进来 String url = "https://www.tianqiapi.com/api?version=v6&appid=55233412&appsecret=2Mm5xcPA&cityid=" + cityid.replace("CN", ""); //获取网络信息 //网络访问需要新开线程进行执行,不影响主线程 HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //读取返回的数据 String data = response.body().string(); //新建gson对象 Gson gson = new Gson(); //解析json数据,初始化inTimeWeather inTimeWeather = gson.fromJson(data, InTimeWeather.class); //json格式化 //初始化天气以后,发送消息,更新ui界面 Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } }); }}
效果图:
在县级下选择桦南,效果如下:
城市id存储
- sharedpreferences
- sqlite(数据库)
cityid:101120901
注意:使用sharedpreferences,使得每次打开app的时候查看上次是否选择城市,如果选择了,无需再选
MainActivity.java
代码部分:
import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.content.SharedPreferences;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import com.example.jnsyq.data.Sheng;import com.example.jnsyq.data.Shi;import com.example.jnsyq.data.Xian;import com.example.jnsyq.utils.HttpUtils;import org.jetbrains.annotations.NotNull;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.IOException;import java.util.ArrayList;import java.util.List;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;public class MainActivity extends AppCompatActivity { //定义3个级别 /* static:静态;final:常量 */ private static final int level_sheng = 0; private static final int level_shi = 1; private static final int level_xian = 2; private int level = 0; //变化 //声明控件 private ListView listView; //ListView private Button buttonBack; //Button private TextView title; //TextView //声明省市县对应的列表 private List<Sheng> ShengList = new ArrayList<>(); private List<Shi> ShiList = new ArrayList<>(); private List<Xian> XianList = new ArrayList<>(); //声明省市县名称列表:数据源 private List<String> nameList = new ArrayList<>(); //创建适配器 private ArrayAdapter<String> adapter; //全局的选中的省市县城市 private Sheng s; private Shi shi; private Xian xian; //消息处理loop //【内存泄漏】 Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //通知ListView数据更改 adapter.notifyDataSetChanged(); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //创建sharedPreferences对象 SharedPreferences sharedPreferences = getSharedPreferences("data", MODE_PRIVATE); String cityid = sharedPreferences.getString("cityid", ""); //如果读取到了cityid,cityid长度大于0 if (cityid.length() > 0) { WeatherActivity.actionStart(MainActivity.this, cityid); } buttonBack = findViewById(R.id.back); //button添加点击操作 buttonBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //点击操作,首先判断当前级别 //如果当前处于县级,返回市级 if (level == level_xian) { level = level_shi; //显示上一级省名称 title.setText(s.getName()); //法1:重新获取一次市级列表// getShi(); //法2:直接遍历市级列表 //将所有的市级名称填到homelist中 nameList.clear(); //ShiList.for回车,自动出 for (Shi shi1 : ShiList) { nameList.add(shi1.getName()); adapter.notifyDataSetChanged(); } } else if (level == level_shi) { level = level_sheng; title.setText("中国"); nameList.clear(); for (Sheng sheng1 : ShengList) { nameList.add(sheng1.getName()); adapter.notifyDataSetChanged(); } } } }); title = findViewById(R.id.title); title.setText("中国"); //调用初始化方法 initListView(); //联网初始化省信息 getSheng(); } /** * 新建初始化ListView方法 */ private void initListView() { //初始化ListView //在布局文件中找到该ListView listView = (ListView) findViewById(R.id.listview); //数据源、ListView、适配器实现绑定,数据和显示实时更新 //初始化适配器,将适配器和数据源绑定在一起 //this:上下文 //simple_list_item_1:简单的布局 //nameList:设置数据源 adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, nameList); //绑定ListView和适配器,ListView设置适配器 listView.setAdapter(adapter); //设置点击操作 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //通过点击的位置获取到点击的对象 //如果当前级别是省级,那么获取省级对象,获取市级对象 if (level == level_sheng) { level = level_shi; s = ShengList.get(position); //点击的哪个省,那么title显示该省名称 title.setText(s.getName()); Log.d("MainActivity", "onItemClick: " + s.getName()); getShi(); } else if (level == level_shi) { level = level_xian; shi = ShiList.get(position); //点击的哪个市,那么title显示该市名称 title.setText(shi.getName()); Log.d("MainActivity", "onItemClick: " + shi.getName()); getXian(); } else if (level == level_xian) { xian = XianList.get(position); Log.d("MainActivity", "onItemClick: " + xian.getName()); //选择city以后,在跳转到天气活动之前进行cityid存储 //获取edit对象,编辑sharedpreferences文件 SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit(); //将cityid存储到文件中 editor.putString("cityid", xian.getWeather_id()); //进行确定,应用,保存 editor.apply(); //跳转到天气显示界面 //法1:// Intent intent = new Intent(MainActivity.this, WeatherActivity.class);// //传递cityid到下一个活动// //将weatherid传递到下一个活动,作为cityid参数// intent.putExtra("cityid", xian.getWeather_id());// startActivity(intent); //法2:启动活动的方法 WeatherActivity.actionStart(MainActivity.this, xian.getWeather_id()); } } }); } /** * 获取省一级的城市列表 */ private void getSheng() { //定义url,接口 String url = "http://guolin.tech/api/china"; //#注意:正常情况下,先创建对象,再调用方法// HttpUtil httpUtil = new HttpUtils();// httpUtil.sendOkhttpRequest(); //每次网络访问时,直接调用sendOkhttpRequest即可 HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) {// e.printStackTrace(); //如果访问失败,输出失败信息 Log.d("MainActivity", "onFailure: 网络访问失败"); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //将网络相应信息转换成字符串型 //该操作只能执行一次 String data = response.body().string();// String data1 = response.body().string(); //错误 //输出日志信息 Log.d("MainActivity", "onResponse: " + data); //解析数据,并生成数据类 try { nameList.clear(); ShengList.clear(); //将json字符串转换为json数组 JSONArray jsonArray = new JSONArray(data); //需处理JSONException,未处理异常【用try/catch包括起来】 //遍历json数字,读取所有的json对象 for (int i = 0; i < jsonArray.length(); i++) { //从json数组中读取json对象 JSONObject shengObject = jsonArray.getJSONObject(i); //创建省一级城市对象 Sheng s = new Sheng(); //设置对应的值 s.setId(shengObject.getInt("id")); s.setName(shengObject.getString("name")); //将省对象添加到列表中 ShengList.add(s); //将省名称添加到名称列表 nameList.add(s.getName()); //发送消息到Loop //通过handleMessage进行消息处理 Message msg = new Message(); msg.what = 0; //消息id号 handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取市级的城市列表 * 法1:方法中缺少变量,可以直接传递进来 */// private void getShi(int shengid) {// //url中省级id号是变量,url不完整// String url = "http://guolin.tech/api/china/" + shengid;// } /** * 获取市级的城市列表 * 法2:①将被选中的省级城市定义为全部变量 * ②在getShi方法中进行读取 */ private void getShi() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId(); HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); ShiList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Shi shi = new Shi(); shi.setId(jsonObject.getInt("id")); shi.setName(jsonObject.getString("name")); ShiList.add(shi); nameList.add(shi.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); } /** * 获取县级的城市列表 */ private void getXian() { //定义url,接口 String url = "http://guolin.tech/api/china/" + s.getId() + "/" + shi.getId(); HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); try { //清空nameList,准备存放数据 nameList.clear(); XianList.clear(); JSONArray jsonArray = new JSONArray(data); for (int i = 0; i < jsonArray.length(); i++) { //获取第i个位置的json对象 JSONObject jsonObject = jsonArray.getJSONObject(i); Xian xian = new Xian(); xian.setId(jsonObject.getInt("id")); xian.setName(jsonObject.getString("name")); xian.setWeather_id(jsonObject.getString("weather_id")); XianList.add(xian); nameList.add(xian.getName()); Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } } catch (JSONException e) { e.printStackTrace(); } } }); }}
获取并显示实时天气【7天天气】
第一步:
activity_weather.xml
<?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:orientation="vertical" tools:context=".WeatherActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary"> <TextView android:id="@+id/title_city" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="20sp" android:textColor="#fff" tools:text="济南"/> <TextView android:id="@+id/title_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:textSize="16sp" android:textColor="#fff" android:layout_marginRight="12dp" android:layout_marginEnd="12dp" tools:text="15:00" /> RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="32dp"> <TextView android:id="@+id/degree" android:textColor="#000" android:textSize="60sp" tools:text="20℃" android:layout_gravity="end" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/weather_info" android:textColor="#000" android:textSize="20sp" tools:text="晴" android:layout_gravity="end" android:layout_width="wrap_content" android:layout_height="wrap_content" /> LinearLayout>LinearLayout>
效果图:
第二步:
WeatherActivity.java
效果图:
第三步:
api:http://www.tianqiapi.com/api?version=v1&appid=72458447&appsecret=E2P8xV9n
新建七日天气数据类Forecast.java,代码如下:
import java.util.List;/** *七日天气数据类 */public class Forecast { /** * cityid : 101250101 * update_time : 2020-08-15 06:52:20 * city : 长沙 * cityEn : changsha * country : 中国 * countryEn : China * data : [{"day":"15日(今天)","date":"2020-08-15","week":"星期六","wea":"晴","wea_img":"qing","air":22,"humidity":76,"air_level":"优","air_tips":"空气很好,可以外出活动,呼吸新鲜空气,拥抱大自然!","alarm":{"alarm_type":"","alarm_level":"","alarm_content":""},"tem1":"36℃","tem2":"27℃","tem":"29℃","win":["南风","南风"],"win_speed":"3-4级转<3级","hours":[{"day":"15日08时","wea":"多云","tem":"29℃","win":"南风","win_speed":"3-4级"},{"day":"15日11时","wea":"晴","tem":"32℃","win":"南风","win_speed":"3-4级"},{"day":"15日14时","wea":"晴","tem":"34℃","win":"南风","win_speed":"3-4级"},{"day":"15日17时","wea":"晴","tem":"35℃","win":"南风","win_speed":"<3级"},{"day":"15日20时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"15日23时","wea":"晴","tem":"29℃","win":"南风","win_speed":"<3级"},{"day":"16日02时","wea":"晴","tem":"28℃","win":"南风","win_speed":"<3级"},{"day":"16日05时","wea":"晴","tem":"27℃","win":"南风","win_speed":"<3级"}],"index":[{"title":"中国人民保险
中暑指数","level":"较易中暑","desc":"长时间户外工作的你要适当调整作业时间,备好遮阳设施,及时补充盐分。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天热风大,可选择低强度运动。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"较不宜","desc":"风力较大,洗车后会蒙上灰尘。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}]},{"day":"16日(明天)","date":"2020-08-16","week":"星期日","wea":"晴","wea_img":"qing","tem1":"36℃","tem2":"27℃","tem":"30℃","win":["南风","南风"],"win_speed":"<3级","hours":[{"day":"16日08时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"16日11时","wea":"晴","tem":"33℃","win":"南风","win_speed":"<3级"},{"day":"16日14时","wea":"晴","tem":"35℃","win":"南风","win_speed":"<3级"},{"day":"16日17时","wea":"晴","tem":"35℃","win":"南风","win_speed":"<3级"},{"day":"16日20时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"16日23时","wea":"晴","tem":"28℃","win":"南风","win_speed":"<3级"},{"day":"17日02时","wea":"晴","tem":"27℃","win":"南风","win_speed":"<3级"},{"day":"17日05时","wea":"晴","tem":"27℃","win":"南风","win_speed":"<3级"}],"index":[{"title":"中国人民保险
中暑指数","level":"较易中暑","desc":"炎炎夏日里,出行尽量穿浅色或素色服装。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天气有点热,运动多补水。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"适宜","desc":"天气较好,适合擦洗汽车。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}]},{"day":"17日(后天)","date":"2020-08-17","week":"星期一","wea":"晴","wea_img":"qing","tem1":"36℃","tem2":"27℃","tem":"29℃","win":["南风","南风"],"win_speed":"<3级","hours":[{"day":"17日08时","wea":"晴","tem":"29℃","win":"南风","win_speed":"<3级"},{"day":"17日11时","wea":"晴","tem":"33℃","win":"南风","win_speed":"<3级"},{"day":"17日14时","wea":"晴","tem":"35℃","win":"南风","win_speed":"<3级"},{"day":"17日17时","wea":"晴","tem":"35℃","win":"南风","win_speed":"<3级"},{"day":"17日20时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"17日23时","wea":"晴","tem":"29℃","win":"南风","win_speed":"<3级"},{"day":"18日02时","wea":"晴","tem":"28℃","win":"南风","win_speed":"<3级"},{"day":"18日05时","wea":"晴","tem":"27℃","win":"南风","win_speed":"<3级"}],"index":[{"title":"中国人民保险
中暑指数","level":"易中暑","desc":"酷暑炎炎,尽量避免在上午10点至下午2点外出。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天气有点热,运动多补水。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"适宜","desc":"天气较好,适合擦洗汽车。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}]},{"day":"18日(周二)","date":"2020-08-18","week":"星期二","wea":"晴","wea_img":"qing","tem1":"36℃","tem2":"28℃","tem":"30℃","win":["南风","南风"],"win_speed":"<3级","hours":[{"day":"18日08时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"18日14时","wea":"晴","tem":"36℃","win":"南风","win_speed":"<3级"},{"day":"18日20时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"19日02时","wea":"晴","tem":"28℃","win":"南风","win_speed":"<3级"}],"index":[{"title":"中国人民保险
中暑指数","level":"较易中暑","desc":"酷热难耐,外出尽量不要打赤膊,通风的棉衫和赤膊相比更有消暑的作用。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天气有点热,运动多补水。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"适宜","desc":"天气较好,适合擦洗汽车。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}]},{"day":"19日(周三)","date":"2020-08-19","week":"星期三","wea":"晴","wea_img":"qing","tem1":"36℃","tem2":"28℃","tem":"30℃","win":["南风","南风"],"win_speed":"<3级","hours":[{"day":"19日08时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"19日14时","wea":"晴","tem":"35℃","win":"南风","win_speed":"<3级"},{"day":"19日20时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"20日02时","wea":"晴","tem":"28℃","win":"南风","win_speed":"<3级"}],"index":[{"title":"中国人民保险
中暑指数","level":"易中暑","desc":"又是蒸桑拿的一天,记得多喝盐开水,随身携带防暑药物。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天气有点热,运动多补水。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"适宜","desc":"天气较好,适合擦洗汽车。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}]},{"day":"20日(周四)","date":"2020-08-20","week":"星期四","wea":"晴","wea_img":"qing","tem1":"37℃","tem2":"29℃","tem":"30℃","win":["南风","南风"],"win_speed":"<3级","hours":[{"day":"20日08时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"20日14时","wea":"晴","tem":"37℃","win":"南风","win_speed":"<3级"},{"day":"20日20时","wea":"晴","tem":"32℃","win":"南风","win_speed":"<3级"},{"day":"21日02时","wea":"晴","tem":"29℃","win":"南风","win_speed":"<3级"}],"index":[{"title":"中国人民保险
中暑指数","level":"易中暑","desc":"夏日炎炎,到户外要配搭帽子和遮阳伞。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天气有点热,运动多补水。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"适宜","desc":"天气较好,适合擦洗汽车。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}]},{"day":"21日(周五)","date":"2020-08-21","week":"星期五","wea":"晴","wea_img":"qing","tem1":"37℃","tem2":"29℃","tem":"31℃","win":["南风","南风"],"win_speed":"<3级","hours":[{"day":"21日08时","wea":"晴","tem":"31℃","win":"南风","win_speed":"<3级"},{"day":"21日14时","wea":"晴","tem":"36℃","win":"南风","win_speed":"<3级"},{"day":"21日20时","wea":"晴","tem":"32℃","win":"南风","win_speed":"<3级"},{"day":"22日02时","wea":"晴","tem":"29℃","win":"南风","win_speed":"<3级"}],"index":[{"title":"中国人民保险
中暑指数","level":"较易中暑","desc":"夏日炎炎,到户外要配搭帽子和遮阳伞。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天气有点热,运动多补水。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"适宜","desc":"天气较好,适合擦洗汽车。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}]}] */ private String cityid; private String update_time; private String city; private String cityEn; private String country; private String countryEn; private List<DataBean> data; public String getCityid() { return cityid; } public void setCityid(String cityid) { this.cityid = cityid; } public String getUpdate_time() { return update_time; } public void setUpdate_time(String update_time) { this.update_time = update_time; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCityEn() { return cityEn; } public void setCityEn(String cityEn) { this.cityEn = cityEn; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCountryEn() { return countryEn; } public void setCountryEn(String countryEn) { this.countryEn = countryEn; } public List<DataBean> getData() { return data; } public void setData(List<DataBean> data) { this.data = data; } public static class DataBean { /** * day : 15日(今天) * date : 2020-08-15 * week : 星期六 * wea : 晴 * wea_img : qing * air : 22 * humidity : 76 * air_level : 优 * air_tips : 空气很好,可以外出活动,呼吸新鲜空气,拥抱大自然! * alarm : {"alarm_type":"","alarm_level":"","alarm_content":""} * tem1 : 36℃ * tem2 : 27℃ * tem : 29℃ * win : ["南风","南风"] * win_speed : 3-4级转<3级 * hours : [{"day":"15日08时","wea":"多云","tem":"29℃","win":"南风","win_speed":"3-4级"},{"day":"15日11时","wea":"晴","tem":"32℃","win":"南风","win_speed":"3-4级"},{"day":"15日14时","wea":"晴","tem":"34℃","win":"南风","win_speed":"3-4级"},{"day":"15日17时","wea":"晴","tem":"35℃","win":"南风","win_speed":"<3级"},{"day":"15日20时","wea":"晴","tem":"30℃","win":"南风","win_speed":"<3级"},{"day":"15日23时","wea":"晴","tem":"29℃","win":"南风","win_speed":"<3级"},{"day":"16日02时","wea":"晴","tem":"28℃","win":"南风","win_speed":"<3级"},{"day":"16日05时","wea":"晴","tem":"27℃","win":"南风","win_speed":"<3级"}] * index : [{"title":"中国人民保险
中暑指数","level":"较易中暑","desc":"长时间户外工作的你要适当调整作业时间,备好遮阳设施,及时补充盐分。"},{"title":"<\/em><\/em><\/em>","level":null,"desc":"天热风大,可选择低强度运动。"},{"title":"健臻·血糖指数","level":"易波动","desc":"气温高,血糖易波动,注意防暑降温。"},{"title":"穿衣指数","level":"炎热","desc":"建议穿短衫、短裤等清凉夏季服装。"},{"title":"洗车指数","level":"较不宜","desc":"风力较大,洗车后会蒙上灰尘。"},{"title":"紫外线指数","level":"很强","desc":"涂擦SPF20以上,PA++护肤品,避强光。"}] */ private String day; private String date; private String week; private String wea; private String wea_img; private int air; private int humidity; private String air_level; private String air_tips; private AlarmBean alarm; private String tem1; private String tem2; private String tem; private String win_speed; private List<String> win; private List<HoursBean> hours; private List<IndexBean> index; public String getDay() { return day; } public void setDay(String day) { this.day = day; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getWeek() { return week; } public void setWeek(String week) { this.week = week; } public String getWea() { return wea; } public void setWea(String wea) { this.wea = wea; } public String getWea_img() { return wea_img; } public void setWea_img(String wea_img) { this.wea_img = wea_img; } public int getAir() { return air; } public void setAir(int air) { this.air = air; } public int getHumidity() { return humidity; } public void setHumidity(int humidity) { this.humidity = humidity; } public String getAir_level() { return air_level; } public void setAir_level(String air_level) { this.air_level = air_level; } public String getAir_tips() { return air_tips; } public void setAir_tips(String air_tips) { this.air_tips = air_tips; } public AlarmBean getAlarm() { return alarm; } public void setAlarm(AlarmBean alarm) { this.alarm = alarm; } public String getTem1() { return tem1; } public void setTem1(String tem1) { this.tem1 = tem1; } public String getTem2() { return tem2; } public void setTem2(String tem2) { this.tem2 = tem2; } public String getTem() { return tem; } public void setTem(String tem) { this.tem = tem; } public String getWin_speed() { return win_speed; } public void setWin_speed(String win_speed) { this.win_speed = win_speed; } public List<String> getWin() { return win; } public void setWin(List<String> win) { this.win = win; } public List<HoursBean> getHours() { return hours; } public void setHours(List<HoursBean> hours) { this.hours = hours; } public List<IndexBean> getIndex() { return index; } public void setIndex(List<IndexBean> index) { this.index = index; } public static class AlarmBean { /** * alarm_type : * alarm_level : * alarm_content : */ private String alarm_type; private String alarm_level; private String alarm_content; public String getAlarm_type() { return alarm_type; } public void setAlarm_type(String alarm_type) { this.alarm_type = alarm_type; } public String getAlarm_level() { return alarm_level; } public void setAlarm_level(String alarm_level) { this.alarm_level = alarm_level; } public String getAlarm_content() { return alarm_content; } public void setAlarm_content(String alarm_content) { this.alarm_content = alarm_content; } } public static class HoursBean { /** * day : 15日08时 * wea : 多云 * tem : 29℃ * win : 南风 * win_speed : 3-4级 */ private String day; private String wea; private String tem; private String win; private String win_speed; public String getDay() { return day; } public void setDay(String day) { this.day = day; } public String getWea() { return wea; } public void setWea(String wea) { this.wea = wea; } public String getTem() { return tem; } public void setTem(String tem) { this.tem = tem; } public String getWin() { return win; } public void setWin(String win) { this.win = win; } public String getWin_speed() { return win_speed; } public void setWin_speed(String win_speed) { this.win_speed = win_speed; } } public static class IndexBean { /** * title : 中国人民保险
中暑指数 * level : 较易中暑 * desc : 长时间户外工作的你要适当调整作业时间,备好遮阳设施,及时补充盐分。 */ private String title; private String level; private String desc; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getLevel() { return level; } public void setLevel(String level) { this.level = level; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } } }}
第四步:
activity_weather.xml
<?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:orientation="vertical" tools:context=".WeatherActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary"> <TextView android:id="@+id/title_city" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="20sp" android:textColor="#fff" tools:text="济南"/> <TextView android:id="@+id/title_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:textSize="16sp" android:textColor="#fff" android:layout_marginRight="12dp" android:layout_marginEnd="12dp" tools:text="15:00" /> RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="32dp"> <TextView android:id="@+id/degree" android:textColor="#000" android:textSize="60sp" tools:text="20℃" android:layout_gravity="end" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/weather_info" android:textColor="#000" android:textSize="20sp" tools:text="晴" android:layout_gravity="end" android:layout_width="wrap_content" android:layout_height="wrap_content" /> LinearLayout> <LinearLayout android:padding="32dp" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#8000"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="预报" android:textColor="#fff" android:textSize="20sp"/> <LinearLayout android:id="@+id/forecast_layout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> LinearLayout> LinearLayout>LinearLayout>
效果图:
forecast_item.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp"> <TextView android:id="@+id/date" android:textSize="16sp" android:text="2020-8-12" android:textColor="#fff" android:gravity="center" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:id="@+id/wea_info" android:textSize="16sp" android:text="晴" android:textColor="#fff" android:gravity="center" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:id="@+id/h_degree" android:textSize="16sp" android:text="30" android:textColor="#fff" android:gravity="center" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:id="@+id/l_degree" android:textSize="16sp" android:text="27" android:textColor="#fff" android:gravity="center" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/>LinearLayout>
layout_weight=“1” 设置权重
第五步:
package com.example.jnsyq;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.LayoutInflater;import android.view.View;import android.widget.LinearLayout;import android.widget.TextView;import com.example.jnsyq.data.Forecast;import com.example.jnsyq.data.InTimeWeather;import com.example.jnsyq.utils.HttpUtils;import com.google.gson.Gson;import org.jetbrains.annotations.NotNull;import java.io.IOException;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;public class WeatherActivity extends AppCompatActivity { private InTimeWeather inTimeWeather; private Forecast forecast; //声明控件 private TextView titleCity; private TextView titleTime; private TextView degree; private TextView weatherInfo; private LinearLayout foreLayout; private String cityid; //private protected public(默认:protected) Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: //调用更新ui方法 updateUi(); break; case 1: //调用7天预报更新方法 updateForecast(); break; default: break; } } }; public static void actionStart(Context context, String cityid) { Intent intent = new Intent(context, WeatherActivity.class); intent.putExtra("cityid", cityid); context.startActivity(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weather); //从布局中找到控件 titleCity = findViewById(R.id.title_city); titleTime = findViewById(R.id.title_time); degree = findViewById(R.id.degree); weatherInfo = findViewById(R.id.weather_info); foreLayout = findViewById(R.id.forecast_layout); //获取意图 Intent intent = getIntent(); //获取上一个活动传递劲来的数据 //初始化cityid的值 cityid = intent.getStringExtra("cityid"); //调用该方法获取数据 getWeatherInfo(); getForecaseInfo(); } private void updateUi() { //设置对应值 titleCity.setText(inTimeWeather.getCity()); titleTime.setText(inTimeWeather.getUpdate_time().split(" ")[1]); degree.setText(inTimeWeather.getTem() + "℃"); weatherInfo.setText(inTimeWeather.getWea()); } private void updateForecast() { //遍历7天数据 //forecast.getData().for 自动出 for (Forecast.DataBean dataBean : forecast.getData()) { //通过布局文件创建view View view = LayoutInflater.from(this).inflate(R.layout.forecast_item, foreLayout, false); //获取布局文件的控件 TextView date = view.findViewById(R.id.date); TextView wea = view.findViewById(R.id.wea_info); TextView hDegree = view.findViewById(R.id.h_degree); TextView lDegree = view.findViewById(R.id.l_degree); //设置值 date.setText(dataBean.getWeek()); wea.setText(dataBean.getWea()); hDegree.setText(dataBean.getTem1()); lDegree.setText(dataBean.getTem2()); //添加布局view foreLayout.addView(view); } } /** * 创建获取实时天气的方法 */ private void getWeatherInfo() { //通过调用api获取天气信息 //直接通过ip地址进行天气信息获取 //cityid:变量,由上一个活动传递进来 String url = "http://www.tianqiapi.com/api?version=v6&appid=72458447&appsecret=E2P8xV9n&cityid=" + cityid.replace("CN", ""); //获取网络信息 //网络访问需要新开线程进行执行,不影响主线程 HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { //读取返回的数据 String data = response.body().string(); //新建gson对象 Gson gson = new Gson(); //解析json数据,初始化inTimeWeather inTimeWeather = gson.fromJson(data, InTimeWeather.class); //json格式化 //初始化天气以后,发送消息,更新ui界面 Message msg = new Message(); msg.what = 0; handler.sendMessage(msg); } }); } /** * 创建获取七日天气数据的方法 */ private void getForecaseInfo() { String url = "http://www.tianqiapi.com/api?version=v1&appid=72458447&appsecret=E2P8xV9n&cityid=" + cityid.replace("CN", ""); HttpUtils.sendOkhttpRequest(url, new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { e.printStackTrace(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { String data = response.body().string(); Gson gson = new Gson(); forecast = gson.fromJson(data, Forecast.class); Message msg = new Message(); msg.what = 1; handler.sendMessage(msg); } }); }}
效果图:
更多相关文章
- Android 对象序列化之 Parcelable 取代 Serializable ?
- Android 对象序列化之追求完美的 Serial
- Android中的适配器(Adapter)
- 带你了解CLR是如何创建运行时对象?
- lambda表达式进行对象结合操作的实例详解
- 值类型对象的两种表示形式
- 克隆对象的方法实例教程
- c#中关于多线程创建对象的示例分享
- asp如何解析json字符串并转化为asp对象