接着上一步的:[https://blog.csdn.net/weixin_44889138/article/details/102748057]
上一步的链接
ListView的改进,因为每次在getView()方法中还是会调用View的findViewById()方法来获取一次控件的实例,写一个内部类,利用**view.setTag()**存储,getTag()取。其实实现的机制跟RecycleView差不多
package com.example.xhhweather;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class CityAdapter extends BaseAdapter {
//
class ViewHolder{
TextView TVcityName;
//删除城市
ImageView ivDelCity;
//选择城市后返回天气界面
ImageView ivQuyCity;
}
private List<CityItem> list;
public CityAdapter(List<CityItem> list){
this.list=list;
}
@Override
public View getView(final int position, View covertView, final ViewGroup viewGroup) {
View view;
ViewHolder viewHolder;
if(covertView==null){
view= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.city_item,viewGroup,false);
viewHolder=new ViewHolder();
viewHolder.TVcityName=view.findViewById(R.id.tv_city_name);
viewHolder.ivQuyCity=view.findViewById(R.id.btn_move);
viewHolder.ivDelCity=view.findViewById(R.id.iv_del_city);
//将viewHolder存入在view中
view.setTag(viewHolder);
}else{
view=covertView;
viewHolder= (ViewHolder) view.getTag();
}
CityItem cityItem= list.get(position);
viewHolder.TVcityName.setText(cityItem.getCityName());
//删除城市
viewHolder.ivDelCity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
list.remove(position);
notifyDataSetChanged();//本身就是adapter
}
});
//移动城市
viewHolder.ivQuyCity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
CityItem city=list.get(position);
Toast.makeText(viewGroup.getContext(),city.getCityPinYin(),Toast.LENGTH_SHORT).show();
}
});
return view;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int i) {
return list.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
}
package com.example.xhhweather;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.example.xhhweather.gson.Weather;
import com.example.xhhweather.gson.WeatherResDaily;
import com.example.xhhweather.gson.WeatherResults;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
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{
private Button btnSelectCity;
private TextView weatherTitleCityname;
private TextView tvFirstDayDate;
private TextView tvFirstDayPhe;
private TextView tvFirstDayHigh;
private TextView tvFirstDayLow;
private TextView tvSecondDayDate;
private TextView tvSecondDayPhe;
private TextView tvSecondDayHigh;
private TextView tvSecondDayLow;
private TextView tvThirdDayDate;
private TextView tvThirdDayPhe;
private TextView tvThirdDayHigh;
private TextView tvThirdDayLow;
private TextView temperatureText;
private TextView caseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initfindViewById();
btnSelectCity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,SelectCity.class);
startActivityForResult(intent,1001);
}
});
}
/**
* 初始化
*/
private void initfindViewById(){
btnSelectCity=findViewById(R.id.manage_city_btn);
weatherTitleCityname=findViewById(R.id.weather_title_cityname);
temperatureText=findViewById(R.id.temperature_text);
caseText=findViewById(R.id.case_text);
tvFirstDayDate=findViewById(R.id.tv_firstday_date);
tvFirstDayPhe=findViewById(R.id.tv_firstday_phe);
tvFirstDayHigh=findViewById(R.id.tv_firstday_high);
tvFirstDayLow=findViewById(R.id.tv_firstday_low);
tvSecondDayDate=findViewById(R.id.tv_secondday_date);
tvSecondDayPhe=findViewById(R.id.tv_secondday_phe);
tvSecondDayHigh=findViewById(R.id.tv_secondday_high);
tvSecondDayLow=findViewById(R.id.tv_secondday_low);
tvThirdDayDate=findViewById(R.id.tv_thirdday_date);
tvThirdDayPhe=findViewById(R.id.tv_thirdday_phe);
tvThirdDayHigh=findViewById(R.id.tv_thirdday_high);
tvThirdDayLow=findViewById(R.id.tv_thirdday_low);
}
/**
* 得到
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==1001 && resultCode==1002){
String cityPinYin=data.getStringExtra("CITYPINYIN");
//Log.e("MainActivity","返回城市的拼音"+cityPinYin);
//心知天气的api
String url="https://api.seniverse.com/v3/weather/daily.json?key=SojsF4VNkV_cTQexq&location=" + cityPinYin + "&language=zh-Hans&unit=c&start=0&days=5";
HttpUtil.sendOkHttpRequest(url, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String weatherData=response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e("MainActivity","得到的数据"+weatherData);
Gson gson =new Gson();
Weather weatherInfo=gson.fromJson(weatherData,Weather.class);
WeatherResults results=weatherInfo.getResults().get(0);
String cityName=results.getLocation().getName();//城市名称
weatherTitleCityname.setText(cityName);
//将3天内的天气数据获得后存入二维数组
String [] [] resultDaily=new String[3][5];
for(int i=0;i<3;i++){
for(int j=0;j<4;){
resultDaily[i][j]=results.getDaily().get(i).getDate();j++;
resultDaily[i][j]=results.getDaily().get(i).getText_day();j++;
resultDaily[i][j]=results.getDaily().get(i).getHigh();j++;
resultDaily[i][j]=results.getDaily().get(i).getLow();j++;
}
}
temperatureText.setText(resultDaily[0][2]+"℃");
caseText.setText(resultDaily[0][1]);
for(int j=0;j<4;){
//Log.e("resultDaily",resultDaily[0][j]);
tvFirstDayDate.setText(resultDaily[0][j]);j++;
tvFirstDayPhe.setText(resultDaily[0][j]);j++;
tvFirstDayHigh.setText(resultDaily[0][j]);j++;
tvFirstDayLow.setText(resultDaily[0][j]);j++;
}
for(int j=0;j<4;){
tvSecondDayDate.setText(resultDaily[1][j]);j++;
tvSecondDayPhe.setText(resultDaily[1][j]);j++;
tvSecondDayHigh.setText(resultDaily[1][j]);j++;
tvSecondDayLow.setText(resultDaily[1][j]);j++;
}
for(int j=0;j<4;){
tvThirdDayDate.setText(resultDaily[2][j]);j++;
tvThirdDayPhe.setText(resultDaily[2][j]);j++;
tvThirdDayHigh.setText(resultDaily[2][j]);j++;
tvThirdDayLow.setText(resultDaily[2][j]);j++;
}
}
});
}
});
}
}
}
package com.example.xhhweather;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class HttpUtil {
public static void sendOkHttpRequest(String url,okhttp3.Callback callback){
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(callback);
}
}
接下来,分析重点
首先看一下心知天气文档,得知需要城市拼音,才能利用api得到不同城市的接口,返回的数据是json格式
访问api需要使用HTTP协议访问网络,那么应该得先想到要用到网络的权限
uses-permission android:name=“android.permission.INTERNET”
这里我用的是OkHttp代替HttpURLConnecion,需要导入依赖
implementation ‘com.squareup.okhttp3:okhttp:3.4.1’
如果不熟悉用法,那就从简单的做起,我介绍怎么简单获得必应图片的每日一图,与本项目有间接的关系(后期用到)
导入这个依赖 implementation ‘com.github.bumptech.glide:glide:4.10.0’,简单快捷可以将图片加载,而且容易理解
建一个HttpUtil类的原因
一个应用程序很可能会在许多地方都使用到网络功能,而发送HTTP请求的代码基本相同,如果每次都去编写,这显然很差劲,将这些通用的网络操作提取到一个公共的类里,并提供一个静态方法
package com.example.atuogetpic;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class HttpUtil {
public static void sendOkHttpRequest(String address,okhttp3.Callback callback){
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder()
.url(address)
.build();
client.newCall(request).enqueue(callback);
}
}
package com.example.atuogetpic;
import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import static android.preference.PreferenceManager.getDefaultSharedPreferences;
public class MainActivity extends AppCompatActivity {
private ImageView bingPicImg;
private Button btnQ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bingPicImg=findViewById(R.id.bing_pic_img);
btnQ=findViewById(R.id.btn);
btnQ.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loadBingPic();
}
});
}
/**
* 加载必应每日一图
*/
private void loadBingPic(){
final String requestBingPic="http://guolin.tech/api/bing_pic";
HttpUtil.sendOkHttpRequest(requestBingPic, new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
final String bingPic=response.body().string();
SharedPreferences.Editor editor=
getSharedPreferences("bing_pic",MODE_PRIVATE).edit();
editor.putString("bing_pic",bingPic);
editor.apply();
runOnUiThread(new Runnable() {
@Override
public void run() {
Glide.with(MainActivity.this).load(bingPic).into(bingPicImg);//加载图片
}
});
}
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
});
}
}
<?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"
tools:context=".MainActivity"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn"
android:text="换图"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/bing_pic_img"
android:src="@drawable/bg"/>
</LinearLayout>
好了,网络请求应该都会了吧
接下来才是重头戏,需要解析json里的数据,但是返回的数据太过复杂(可以看心知天气文档)
可以用gson解析 ,需要导入依赖
implementation ‘com.google.code.gson:gson:2.8.5’
它主要可以将一段json格式的字符串自动映射成一个对象,不用我们去编写代码解析
{
“results”:[
{
“location”:{“id”:“WTW3SJ5ZBJUY”,“name”:“上海”,“country”:“CN”,“path”:“上海,上海,中国”,“timezone”:“Asia/Shanghai”,“timezone_offset”:"+08:00"}
,“daily”:[
{ “date”:“2019-10-28”,“text_day”:“多云”,“code_day”:“4”,“text_night”:“晴”,“code_night”:“1”,“high”:“21”,“low”:“14”,“precip”:"",“wind_direction”:“西”,“wind_direction_degree”:“270”,“wind_speed”:“16.20”,“wind_scale”:“3”}
,{“date”:“2019-10-29”,“text_day”:“晴”,“code_day”:“0”,“text_night”:“晴”,“code_night”:“1”,“high”:“22”,“low”:“14”,“precip”:"",“wind_direction”:“东北”,“wind_direction_degree”:“45”,“wind_speed”:“25.20”,“wind_scale”:“4”}
,{“date”:“2019-10-30”,“text_day”:“晴”,“code_day”:“0”,“text_night”:“晴”,“code_night”:“1”,“high”:“22”,“low”:“14”,“precip”:"",“wind_direction”:“东”,“wind_direction_degree”:“90”,“wind_speed”:“16.20”,“wind_scale”:“3”}
],
“last_update”:“2019-10-28T11:17:53+08:00”
}
]
}
解析这个json数据
1.{ }里面是一个一个results数组,就应该写成列表,而weather类表示 { }
package com.example.xhhweather.gson;
import java.util.List;
public class Weather {
private List<WeatherResults> results;//命名一定要与数据中的相同,一定要对应
public List<WeatherResults> getResults() {
return results;
}
public void setResults(List<WeatherResults> results) {
this.results = results;
}
@Override
public String toString() {
return "Weather{" +
"results=" + results +
'}';
}
}
2.建一个WeatherResults类,results数组里面又有"location":{},“daily”:[],“last_update”:一个字符串
package com.example.xhhweather.gson;
import java.util.List;
public class WeatherResults {
private WeatherResLocation location;//对应location:{},命名一定要与数据中的相同,一定要对应
private List<WeatherResDaily> daily;//对应daily:数组
private String last_update;//对应"last_update":一个字符串
public WeatherResLocation getLocation() {
return location;
}
public List<WeatherResDaily> getDaily() {
return daily;
}
public String getLast_update() {
return last_update;
}
public void setLocation(WeatherResLocation location) {
this.location = location;
}
public void setDaily(List<WeatherResDaily> daily) {
this.daily = daily;
}
public void setLast_update(String last_update) {
this.last_update = last_update;
}
@Override
public String toString() {
return "WeatherResults{" +
"location=" + location +
", daily=" + daily +
", last_update='" + last_update + '\'' +
'}';
}
}
package com.example.xhhweather.gson;
public class WeatherResDaily {
private String date;
private String text_day;
private String code_day;
private String text_night;
private String code_night;
private String high;
private String low;
private String precip;
private String wind_direction;
private String wind_direction_degree;
private String wind_speed;
private String wind_scale;
public String getDate() {
return date;
}
public String getText_day() {
return text_day;
}
public String getCode_day() {
return code_day;
}
public String getText_night() {
return text_night;
}
public String getCode_night() {
return code_night;
}
public String getHigh() {
return high;
}
public String getLow() {
return low;
}
public String getPrecip() {
return precip;
}
public String getWind_direction() {
return wind_direction;
}
public String getWind_direction_degree() {
return wind_direction_degree;
}
public String getWind_speed() {
return wind_speed;
}
public String getWind_scale() {
return wind_scale;
}
public void setDate(String date) {
this.date = date;
}
public void setText_day(String text_day) {
this.text_day = text_day;
}
public void setCode_day(String code_day) {
this.code_day = code_day;
}
public void setText_night(String text_night) {
this.text_night = text_night;
}
public void setCode_night(String code_night) {
this.code_night = code_night;
}
public void setHigh(String high) {
this.high = high;
}
public void setLow(String low) {
this.low = low;
}
public void setPrecip(String precip) {
this.precip = precip;
}
public void setWind_direction(String wind_direction) {
this.wind_direction = wind_direction;
}
public void setWind_direction_degree(String wind_direction_degree) {
this.wind_direction_degree = wind_direction_degree;
}
public void setWind_speed(String wind_speed) {
this.wind_speed = wind_speed;
}
public void setWind_scale(String wind_scale) {
this.wind_scale = wind_scale;
}
@Override
public String toString() {
return "WeatherResDaily{" +
"date='" + date + '\'' +
", text_day='" + text_day + '\'' +
", code_day='" + code_day + '\'' +
", text_night='" + text_night + '\'' +
", code_night='" + code_night + '\'' +
", high='" + high + '\'' +
", low='" + low + '\'' +
", precip='" + precip + '\'' +
", wind_direction='" + wind_direction + '\'' +
", wind_direction_degree='" + wind_direction_degree + '\'' +
", wind_speed='" + wind_speed + '\'' +
", wind_scale='" + wind_scale + '\'' +
'}';
}
}
package com.example.xhhweather.gson;
public class WeatherResLocation {
private String id;
private String name;
private String country;
private String path;
private String timezone;
private String timezone_offset;
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getCountry() {
return country;
}
public String getPath() {
return path;
}
public String getTimezone() {
return timezone;
}
public String getTimezone_offset() {
return timezone_offset;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setCountry(String country) {
this.country = country;
}
public void setPath(String path) {
this.path = path;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public void setTimezone_offset(String timezone_offset) {
this.timezone_offset = timezone_offset;
}
@Override
public String toString() {
return "WeatherResLocation{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", country='" + country + '\'' +
", path='" + path + '\'' +
", timezone='" + timezone + '\'' +
", timezone_offset='" + timezone_offset + '\'' +
'}';
}
}
代码可以自动生成,右键点击general(首先要先命名)
Gson gson =new Gson();
Weather weatherInfo=gson.fromJson(weatherData,Weather.class);
weatherData为你发起请求后返回的json数据
这样就可以得到你想要的数据
那就先到这了,代码会在下一步开源