Android learning column - actual combat project cool Europe weather display weather information

Series articles

Tip: go to the Android learning column and watch more!
Click me directly – > Android learning column
In this project, pay attention to the modification of the package name prefix and change it to your own. My package name is:
com.example.coolweather, otherwise an error will be reported.

preface

This sub topic: displaying weather information
Project practice inherits the previous articles
Last article
Android learning column - actual combat project cool weather (2) traversing the data of provinces, cities and counties across the country
Portal:

https://blog.csdn.net/u011027547/article/details/121508186

Realization effect

Choose Zhejiang → Shaoxing → Shaoxing (the second Shaoxing City here, Shaoxing City)


Project structure

There are several packages under the com.coolweather.android package

  1. The db package is used to store the code related to the database model
  2. The gson package is used to store the code related to the gson model
  3. The service package is used to store service related code
  4. The util package is used to store tool related code.

1. Define GSON entity class

Returns the approximate format of the data

{
    "HeWeather": [{
        "status": "ok",
        "basic": {},
        "aqi": {},
        "now": {},
        "suggestion": {},
        "daily_forecast": []
    }]
}

basic, aqi, now, suggestion and daily_ There will be specific contents inside the forecast, so we can define these five parts into five entity classes.

1.1 create a Basic class under the gson package

The original specific content in basic

"basic":{
    "city":"Suzhou",
    "id":"CN101190401",
    "update":{
    "loc":"2016-08-08 21:58"
    }
}

Some fields in JSON may not be suitable to be named directly as Java fields, so the @ SerializedName annotation is used here to establish a mapping relationship between JSON fields and Java fields.
Create a Basic class under the gson package

package com.example.coolweather.gson;

import com.google.gson.annotations.SerializedName;

public class Basic {
    @SerializedName("city")
    public String cityName;
    @SerializedName("id")
    public String weatherId;
    public Update update;
    public class Update {
        @SerializedName("loc")
        public String updateTime;
    }
}

Create an AQI class under 1.2gson package

Original details in AQI

"aqi":{
        "city":{
        "aqi":"44",
        "pm25":"13"
        }
    }

Create a new AQI class under the gson package

package com.example.coolweather.gson;

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

Create a Now class under 1.3gson package

Original details in Now

"now":{
	"tmp":"29",
	"cond":{
		"txt":"shower"
	}
}

Create a new Now class under the gson package

package com.example.coolweather.gson;

import com.google.gson.annotations.SerializedName;

public class Now {
    @SerializedName("tmp")
    public String temperature;
    @SerializedName("cond")
    public More more;

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

Create a Suggestion class under 1.4gson package

Original specific content in Suggestion

"suggestion":{
    "comf":{
        "txt":"It's hot during the day. Although there is rain, it still can't weaken the summer heat brought by higher temperature. This kind of weather will make you feel uncomfortable."
    },
    "cw":{
        "txt":"It is not suitable to wash the car. It will rain in the next 24 hours. If you wash the car during this period, the rain and muddy water on the road may dirty your car again."
    },
    "sport":{
        "txt":"With precipitation and strong wind, it is recommended that you take low-intensity exercise indoors; If you insist on outdoor sports, please choose a shelter from rain and wind."
    }
}

Create a Suggestion class under the gson package

package com.example.coolweather.gson;

import com.google.gson.annotations.SerializedName;

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

    public class Comfort {
        @SerializedName("txt")
        public String info;
    }

    public class CarWash {
        @SerializedName("txt")
        public String info;
    }

    public class Sport {
        @SerializedName("txt")
        public String info;
    }
}

Create a Forecast class under the 1.5gson package

The next data item is daily_forecast is special.
Original details in Forecast

"daily_forecast": [{
        "date": "2016-08-08",
        "cond": {
            "txt_d": "shower"
        },
        "tmp": {
            "max": "34",
            "min": "27"
        }
    },
    {
        "date": "2016-08-09",
        "cond": {
            "txt_d": "cloudy"
        },
        "tmp": {
            "max": "35",
            "min": "29"
        }
    },
    ...
}]

Create a new Forecast class under the gson package
daily_ The forecast contains an array, and each item in the array represents the weather information of the next day. In this case, we only need to define the entity class of single day weather, and then use the collection type when declaring the entity class reference.

package com.example.coolweather.gson;

import com.google.gson.annotations.SerializedName;

public class Forecast {
    public String date;
    @SerializedName("tmp")
    public Temperature temperature;
    @SerializedName("cond")
    public More more;

    public class Temperature {
        public String max;
        public String min;
    }

    public class More {
        @SerializedName("txt_d")
        public String info;
    }
}

Create a Weather class under the 1.6gson package

Put basic, aqi, now, suggestion and daily_ All entity classes corresponding to forecast have been created. Next, you need to create a general instance class to refer to each entity class just created.

In the Weather class, we define Basic, AQI, Now, Suggestion, and
The Forecast class is referenced. Among them, due to daily_ The Forecast contains a
An array, so the List collection is used here to refer to the Forecast class. In addition, the days returned
The gas data also contains a status data. If it succeeds, it will return ok, and if it fails, it will return the specific status
For this reason, you also need to add a corresponding status field here.

Create a new Weather class under the gson package

package com.example.coolweather.gson;

import com.google.gson.annotations.SerializedName;

import java.util.List;

public class Weather {
    public String status;
    public Basic basic;
    public AQI aqi;
    public Now now;
    public Suggestion suggestion;
    @SerializedName("daily_forecast")
    public List<Forecast> forecastList;
}

2. Prepare weather interface

Create an activity to display weather information

First, create an Activity to display weather information. Right click the com.coolweather.android package → New → Activity → Empty Activity to create a WeatherActivity and specify the layout name as activity_weather.xml.

Since all weather information will be displayed on the same interface, activity_weather.xml will be a long layout file. In order to prevent the code from being chaotic, the layout technology is used, that is, different parts of the interface are written in different layout files, and then integrated into the activity by introducing layout_ In weather.xml, so the whole layout file will appear very neat.

2.1 create a new title.xml

Right click res/layout → New → Layout resource file to create a New title.xml as the header
game

Two textviews are placed in the header layout. One displays the city name in the middle and the other displays the update time on the right.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize">

    <TextView
        android:id="@+id/title_city"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="#fff"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/title_update_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:textColor="#fff"
        android:textSize="16sp" />
</RelativeLayout>

2.2 create a new now.xml

Create a new now.xml as the layout of the current weather information.

Two textviews are also placed in the layout of the current weather information, one for displaying the current weather information
Temperature, one used to display the weather profile.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="15dp">
    <TextView
        android:id="@+id/degree_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end"
        android:textColor="#fff"
        android:textSize="60sp" />
    <TextView
        android:id="@+id/weather_info_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end"
        android:textColor="#fff"
        android:textSize="20sp" />
</LinearLayout>

2.3 create a new forecast.xml

Create a new forecast.xml as the layout of weather information in the next few days

The outermost layer of the interior uses LinearLayout to define a translucent background, then uses TextView to define a title, and then uses a LinearLayout to define a layout for displaying weather information for the next few days. However, nothing is put into the layout because it is dynamically added in the code according to the data returned by the server.

<?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="15dp"
    android:background="#8000"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:text="prediction"
        android:textColor="#fff"
        android:textSize="20sp" />

    <LinearLayout
        android:id="@+id/forecast_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"></LinearLayout>
</LinearLayout>

2.4 create a new forecast_item.xml

Define a sub item layout forecast of future weather information_ item.xml

Four textviews are placed in the sub item layout. One is used to display the weather forecast date, one is used to display the weather profile, and the other two are used to display the maximum temperature and minimum temperature of the day respectively.

<?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="15dp">

    <TextView
        android:id="@+id/date_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_weight="2"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/info_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_weight="1"
        android:gravity="center"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/max_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="right"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/min_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="right"
        android:textColor="#fff" />
</LinearLayout>

2.5 create a new aqi.xml

Create aqi.xml as the layout of air quality information.

It is the same as before. Use LinearLayout to define a translucent background, and then use TextView to define a title. Next, a layout with left-right bisection and center alignment is realized by nesting LinearLayout and RelativeLayout, which are used to display AQI index and PM 2.5 index respectively. I believe you just need to take a closer look, this layout is still very easy to understand.

<?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="15dp"
    android:background="#8000"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:text="air quality"
        android:textColor="#fff"
        android:textSize="20sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="15dp">

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/aqi_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:textColor="#fff"
                    android:textSize="40sp" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:text="AQI index"
                    android:textColor="#fff" />
            </LinearLayout>
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/pm25_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:textColor="#fff"
                    android:textSize="40sp" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:text="PM2.5 index"
                    android:textColor="#fff" />
            </LinearLayout>
        </RelativeLayout>
    </LinearLayout>
</LinearLayout>

2.6 create a suggestion.xml

Create suggestion.xml as the layout of life suggestion information

First, a translucent background and a title are defined, and then three textviews are used to display the relevant data of comfort, car washing index and sports suggestions.

<?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="15dp"
    android:background="#8000"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        android:text="Life advice"
        android:textColor="#fff"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/comfort_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/car_wash_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/sport_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="15dp"
        android:textColor="#fff" />
</LinearLayout>

2.7 create a new forecast_item.xml

The layout files for each part of the weather interface are written, and then they are introduced into the activity_weather.xml.

First, the outermost layout uses a FrameLayout and sets its background color to colorPrimary. Then a ScrollView is nested in the FrameLayout because there are many contents in the weather interface. Using ScrollView allows us to view the contents outside the screen by scrolling. Because only one direct sub layout is allowed inside the ScrollView, a vertical LinearLayout is nested here, and then all the layouts just defined are introduced one by one in the LinearLayout.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">

    <ScrollView
        android:id="@+id/weather_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never"
        android:scrollbars="none">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <include layout="@layout/title" />

            <include layout="@layout/now" />

            <include layout="@layout/forecast" />

            <include layout="@layout/aqi" />

            <include layout="@layout/suggestion" />
        </LinearLayout>
    </ScrollView>
</FrameLayout>

3. Display the weather on the interface

3.1 add a method for parsing weather JSON data

Add a method to the Utility class to parse weather JSON data.

In the handleWeatherResponse() method, the main content in the weather data is parsed through JSONObject and JSONArray.

Added code

    /**
     * Parse the returned JSON data into a Weather entity class
     */
    public static Weather handleWeatherResponse(String response) {
        try {
            JSONObject jsonObject = new JSONObject(response);
            JSONArray jsonArray = jsonObject.getJSONArray("HeWeather");
            String weatherContent = jsonArray.getJSONObject(0).toString();
            return new Gson().fromJson(weatherContent, Weather.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

All codes

package com.example.coolweather.util;

import android.text.TextUtils;

import com.example.coolweather.db.City;
import com.example.coolweather.db.County;
import com.example.coolweather.db.Province;
import com.example.coolweather.gson.Weather;
import com.google.gson.Gson;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class Utility {
    /**
     * Parse and process the provincial data returned by the server
     */
    public static boolean handleProvinceResponse(String response) {
        if (!TextUtils.isEmpty(response)) {
            try {
                JSONArray allProvinces = new JSONArray(response);
                for (int i = 0; i < allProvinces.length(); i++) {
                    JSONObject provinceObject = allProvinces.getJSONObject(i);
                    Province province = new Province();
                    province.setProvinceName(provinceObject.getString("name"));
                    province.setProvinceCode(provinceObject.getInt("id"));
                    province.save();
                }
                return true;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * Parse and process the municipal data returned by the server
     */
    public static boolean handleCityResponse(String response, int provinceId) {
        if (!TextUtils.isEmpty(response)) {
            try {
                JSONArray allCities = new JSONArray(response);
                for (int i = 0; i < allCities.length(); i++) {
                    JSONObject cityObject = allCities.getJSONObject(i);
                    City city = new City();
                    city.setCityName(cityObject.getString("name"));
                    city.setCityCode(cityObject.getInt("id"));
                    city.setProvinceId(provinceId);
                    city.save();
                }
                return true;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * Parse and process the data returned by the server
     */
    public static boolean handleCountyResponse(String response, int cityId) {
        if (!TextUtils.isEmpty(response)) {
            try {
                JSONArray allCounties = new JSONArray(response);
                for (int i = 0; i < allCounties.length(); i++) {
                    JSONObject countyObject = allCounties.getJSONObject(i);
                    County county = new County();
                    county.setCountyName(countyObject.getString("name"));
                    county.setWeatherId(countyObject.getString("weather_id"));
                    county.setCityId(cityId);
                    county.save();
                }
                return true;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * Parse the returned JSON data into a Weather entity class
     */
    public static Weather handleWeatherResponse(String response) {
        try {
            JSONObject jsonObject = new JSONObject(response);
            JSONArray jsonArray = jsonObject.getJSONArray("HeWeather");
            String weatherContent = jsonArray.getJSONObject(0).toString();
            return new Gson().fromJson(weatherContent, Weather.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

3.2 modify the code in WeatherActivity

We have previously defined the corresponding GSON entity classes according to the above data format, so we can directly convert JSON data into Weather objects by calling the fromJson() method. The next work is how to request Weather data in the activity and display the data on the interface.

In the onCreate() method, you still get some instances of the control first, and then try to read the Weather data from the local cache. Then there must be no cache for the first time, so the Weather id will be taken from Intent and the requestWeather() method will be called to request Weather data from the server. Note that when requesting data, first hide the ScrollView, otherwise the interface of empty data will look strange. In the requestWeather() method, we first use the Weather id passed in the parameter and the API Key we applied for to assemble an interface address, and then call the HttpUtil.sendOkHttpRequest() method to send a request to the address. The server will return the Weather information of the corresponding city in JSON format. Then, in the onResponse() callback, we first call the Utility.handleWeatherResponse() method to convert the returned JSON data into a Weather object, and then switch the current thread to the main thread. Then make a judgment. If the status returned by the server is ok, it indicates that the Weather request is successful. At this time, cache the returned data into SharedPreferences, and call showWeatherInfo() method to display the content. The logic in the showweatherinfo () method is relatively simple. In fact, it is to obtain data from the Weather object and display it on the corresponding control. Note that in the Weather forecast for the next few days, we use a for loop to process the daily Weather information, and dynamically load the forecast in the loop_ Item.xml layout and set the corresponding data, and then add it to the parent layout. After setting all the data, remember to make the ScrollView visible again. In this way, we will sort out all the logic when entering WeatherActivity for the first time. The next time we enter WeatherActivity, because the cache already exists, we will directly parse and display the Weather data instead of initiating the network request again.

package com.example.coolweather;

import androidx.appcompat.app.AppCompatActivity;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.coolweather.gson.Forecast;
import com.example.coolweather.gson.Weather;
import com.example.coolweather.util.HttpUtil;
import com.example.coolweather.util.Utility;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class WeatherActivity extends AppCompatActivity {
    private ScrollView weatherLayout;
    private TextView titleCity;
    private TextView titleUpdateTime;
    private TextView degreeText;
    private TextView weatherInfoText;
    private LinearLayout forecastLayout;
    private TextView aqiText;
    private TextView pm25Text;
    private TextView comfortText;
    private TextView carWashText;
    private TextView sportText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_weather);
// Initialize each control
        weatherLayout = (ScrollView) findViewById(R.id.weather_layout);
        titleCity = (TextView) findViewById(R.id.title_city);
        titleUpdateTime = (TextView) findViewById(R.id.title_update_time);
        degreeText = (TextView) findViewById(R.id.degree_text);
        weatherInfoText = (TextView) findViewById(R.id.weather_info_text);
        forecastLayout = (LinearLayout) findViewById(R.id.forecast_layout);
        aqiText = (TextView) findViewById(R.id.aqi_text);
        pm25Text = (TextView) findViewById(R.id.pm25_text);
        comfortText = (TextView) findViewById(R.id.comfort_text);
        carWashText = (TextView) findViewById(R.id.car_wash_text);
        sportText = (TextView) findViewById(R.id.sport_text);
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences
                (this);
        String weatherString = prefs.getString("weather", null);
        if (weatherString != null) {
// Directly parse weather data when there is cache
            Weather weather = Utility.handleWeatherResponse(weatherString);
            showWeatherInfo(weather);
        } else {
// Go to the server to query the weather when there is no cache
            String weatherId = getIntent().getStringExtra("weather_id");
            weatherLayout.setVisibility(View.INVISIBLE);
            requestWeather(weatherId);
        }
    }

    /**
     * Request city weather information according to weather id
     */
    public void requestWeather(final String weatherId) {
        String weatherUrl = "http://guolin.tech/api/weather?cityid=" +
                weatherId + "&key=bc0418b57b2d4918819d3974ac1285d9";
        HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() {
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseText = response.body().string();
                final Weather weather = Utility.handleWeatherResponse(responseText);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (weather != null && "ok".equals(weather.status)) {
                            SharedPreferences.Editor editor = PreferenceManager
                                    .getDefaultSharedPreferences(WeatherActivity.this)
                                    .edit();
                            editor.putString("weather", responseText);
                            editor.apply();
                            showWeatherInfo(weather);
                        } else {
                            Toast.makeText(WeatherActivity.this, "Failed to get weather information",
                                    Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }

            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(WeatherActivity.this, "Failed to get weather information",
                                Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
    }

    /**
     * Process and display the data in the Weather entity class
     */
    private void showWeatherInfo(Weather weather) {
        String cityName = weather.basic.cityName;
        String updateTime = weather.basic.update.updateTime.split(" ")[1];
        String degree = weather.now.temperature + "℃";
        String weatherInfo = weather.now.more.info;
        titleCity.setText(cityName);
        titleUpdateTime.setText(updateTime);
        degreeText.setText(degree);
        weatherInfoText.setText(weatherInfo);
        forecastLayout.removeAllViews();
        for (Forecast forecast : weather.forecastList) {
            View view = LayoutInflater.from(this).inflate(R.layout.forecast_item, forecastLayout, false);
            TextView dateText = (TextView) view.findViewById(R.id.date_text);
            TextView infoText = (TextView) view.findViewById(R.id.info_text);
            TextView maxText = (TextView) view.findViewById(R.id.max_text);
            TextView minText = (TextView) view.findViewById(R.id.min_text);
            dateText.setText(forecast.date);
            infoText.setText(forecast.more.info);
            maxText.setText(forecast.temperature.max);
            minText.setText(forecast.temperature.min);
            forecastLayout.addView(view);
        }
        if (weather.aqi != null) {
            aqiText.setText(weather.aqi.city.aqi);
            pm25Text.setText(weather.aqi.city.pm25);
        }
        String comfort = "Comfort:" + weather.suggestion.comfort.info;
        String carWash = "Car wash index:" + weather.suggestion.carWash.info;
        String sport = "Exercise suggestions:" + weather.suggestion.sport.info;
        comfortText.setText(comfort);
        carWashText.setText(carWash);
        sportText.setText(sport);
        weatherLayout.setVisibility(View.VISIBLE);
    }
}

3.3 modify ChooseAreaFragment

Jump from the list interface of provinces, cities and counties to the weather interface and modify ChooseAreaFragment

An if judgment is added to the onItemClick() method if the current level is level_ Country, start WeatherActivity and pass the weather id of the currently selected county.

Modified listView.setOnItemClickListener method

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position,
                                    long id) {
                if (currentLevel == LEVEL_PROVINCE) {
                    selectedProvince = provinceList.get(position);
                    queryCities();
                } else if (currentLevel == LEVEL_CITY) {
                    selectedCity = cityList.get(position);
                    queryCounties();
                } else if (currentLevel == LEVEL_COUNTY) {
                    String weatherId = countyList.get(position).getWeatherId();
                    Intent intent = new Intent(getActivity(), WeatherActivity.
                            class);
                    intent.putExtra("weather_id", weatherId);
                    startActivity(intent);
                    getActivity().finish();
                }
            }

        });

Complete code

package com.example.coolweather;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.coolweather.R;
import com.example.coolweather.db.City;
import com.example.coolweather.db.County;
import com.example.coolweather.db.Province;
import com.example.coolweather.util.HttpUtil;
import com.example.coolweather.util.Utility;

import org.litepal.crud.DataSupport;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import androidx.fragment.app.Fragment;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class ChooseAreaFragment extends Fragment {
    public static final int LEVEL_PROVINCE = 0;
    public static final int LEVEL_CITY = 1;
    public static final int LEVEL_COUNTY = 2;
    private ProgressDialog progressDialog;
    private TextView titleText;
    private Button backButton;
    private ListView listView;
    private ArrayAdapter<String> adapter;
    private List<String> dataList = new ArrayList<>();
    /**
     * Province list
     */
    private List<Province> provinceList;
    /**
     * City list
     */
    private List<City> cityList;
    /**
     * County list
     */
    private List<County> countyList;
    /**
     * Selected provinces
     */
    private Province selectedProvince;
    /**
     * Selected city
     */
    private City selectedCity;
    /**
     * Currently selected level
     */
    private int currentLevel;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.choose_area, container, false);
        titleText = (TextView) view.findViewById(R.id.title_text);
        backButton = (Button) view.findViewById(R.id.back_button);
        listView = (ListView) view.findViewById(R.id.list_view);
        adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, dataList);
        listView.setAdapter(adapter);
        return view;
    }
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position,
                                    long id) {
                if (currentLevel == LEVEL_PROVINCE) {
                    selectedProvince = provinceList.get(position);
                    queryCities();
                } else if (currentLevel == LEVEL_CITY) {
                    selectedCity = cityList.get(position);
                    queryCounties();
                } else if (currentLevel == LEVEL_COUNTY) {
                    String weatherId = countyList.get(position).getWeatherId();
                    Intent intent = new Intent(getActivity(), WeatherActivity.
                            class);
                    intent.putExtra("weather_id", weatherId);
                    startActivity(intent);
                    getActivity().finish();
                }
            }

        });
        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (currentLevel == LEVEL_COUNTY) {
                    queryCities();
                } else if (currentLevel == LEVEL_CITY) {
                    queryProvinces();
                }
            }
        });
        queryProvinces();
    }
    /**
     * Query all provinces in the country, give priority to query from the database, and then query on the server if there is no query
     */
    private void queryProvinces() {
        titleText.setText("China");
        backButton.setVisibility(View.GONE);
        provinceList = DataSupport.findAll(Province.class);
        if (provinceList.size() > 0) {
            dataList.clear();
            for (Province province : provinceList) {
                dataList.add(province.getProvinceName());
            }
            adapter.notifyDataSetChanged();
            listView.setSelection(0);
            currentLevel = LEVEL_PROVINCE;
        } else {
            String address = "http://guolin.tech/api/china";
            queryFromServer(address, "province");
        }
    }
    /**
     * Query: select all cities in the province and query from the database first. If there is no query, query on the server again
     */
    private void queryCities() {
        titleText.setText(selectedProvince.getProvinceName());
        backButton.setVisibility(View.VISIBLE);
        cityList = DataSupport.where("provinceid = ?", String.valueOf(selectedProvince.getId())).find(City.class);
        if (cityList.size() > 0) {
            dataList.clear();
            for (City city : cityList) {dataList.add(city.getCityName());
            }
            adapter.notifyDataSetChanged();
            listView.setSelection(0);
            currentLevel = LEVEL_CITY;
        } else {
            int provinceCode = selectedProvince.getProvinceCode();
            String address = "http://guolin.tech/api/china/" + provinceCode;
            queryFromServer(address, "city");
        }
    }
    /**
     * Query: select all counties in the city and give priority to query from the database. If not, query on the server
     */
    private void queryCounties() {
        titleText.setText(selectedCity.getCityName());
        backButton.setVisibility(View.VISIBLE);
        countyList = DataSupport.where("cityid = ?", String.valueOf(selectedCity.
                getId())).find(County.class);
        if (countyList.size() > 0) {
            dataList.clear();
            for (County county : countyList) {
                dataList.add(county.getCountyName());
            }
            adapter.notifyDataSetChanged();
            listView.setSelection(0);
            currentLevel = LEVEL_COUNTY;
        } else {
            int provinceCode = selectedProvince.getProvinceCode();
            int cityCode = selectedCity.getCityCode();
            String address = "http://guolin.tech/api/china/" + provinceCode + "/" +
                    cityCode;
            queryFromServer(address, "county");
        }
    }
    /**
     * Query provincial, city and county data from the server according to the incoming address and type
     */
    private void queryFromServer(String address, final String type) {
        showProgressDialog();
        HttpUtil.sendOkHttpRequest(address, new Callback() {
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String responseText = response.body().string();
                boolean result = false;
                if ("province".equals(type)) {result = Utility.handleProvinceResponse(responseText);
                } else if ("city".equals(type)) {
                    result = Utility.handleCityResponse(responseText,
                            selectedProvince.getId());
                } else if ("county".equals(type)) {
                    result = Utility.handleCountyResponse(responseText,
                            selectedCity.getId());
                }
                if (result) {
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            closeProgressDialog();
                            if ("province".equals(type)) {
                                queryProvinces();
                            } else if ("city".equals(type)) {
                                queryCities();
                            } else if ("county".equals(type)) {
                                queryCounties();
                            }
                        }
                    });
                }
            }
            @Override
            public void onFailure(Call call, IOException e) {
// Return to the main thread processing logic through the runOnUiThread() method
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        closeProgressDialog();
                        Toast.makeText(getContext(), "Loading failed", Toast.LENGTH_SHORT).
                                show();
                    }
                });
            }
        });
    }
    /**
     * Show progress dialog box
     */
    private void showProgressDialog() {
        if (progressDialog == null) {
            progressDialog = new ProgressDialog(getActivity());
            progressDialog.setMessage("Loading...");
            progressDialog.setCanceledOnTouchOutside(false);}
        progressDialog.show();
    }
    /**
     * Close the progress dialog box
     */
    private void closeProgressDialog() {
        if (progressDialog != null) {
            progressDialog.dismiss();
        }
    }


}

3.4 modifying MainActivity

Add a judgment of cached data in MainActivity.

At the beginning of the onCreate() method, first read the cached data from the SharedPreferences file. If it is not null, it means that the weather data has been requested before. There is no need for the user to select the city again, but directly jump to the WeatherActivity.

package com.example.coolweather;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences
                (this);
        if (prefs.getString("weather", null) != null) {
            Intent intent = new Intent(this, WeatherActivity.class);
            startActivity(intent);
            finish();
        }
    }
}

Appendix. References

The first line of code 14.5 displays weather information

Download resources

gitee address

https://gitee.com/miao-zehao/cool-weather

Example of displaying weather information for Android learner's actual combat project cool weather (3)

summary

If you like, give me a 👍, Pay attention! Continue to share with you the problems encountered in the process of typing code!

Tags: Java Android Android Studio

Posted on Sat, 27 Nov 2021 17:06:51 -0500 by rupertbj