Android簡易天氣預報App

先看下app效果圖:

        App介紹:首次啓動應用時列表顯示全國34個省份及直轄市包括港澳臺,如果選擇省份進入所在省份下的市列表,如果再選擇市項進入該市下所有的區或縣(包括該市)列表,如果再選擇該列表下的項就顯示該區域的天氣預報界面。圖5從左滑出側邊欄可以選擇其他城市。如果是非首次啓動,則顯示上次選擇的城市天氣預報界面(比如退出時顯示廣州的天氣預報界面即圖4,再次進入時仍顯示該界面)。

具體app功能實現:

1.獲取全國城市列表(圖1到圖3)

       想羅列出中國所有的省份,只需要訪問地址:http://guolin.tech/api/china,服務器會返回一段JSON格式的數據,包含中國所有省份名稱以及省份id。如果想知道某個省份內有哪些城市,比如江蘇的id是16,訪問地址:http://guolin.tech/api/china/16。只需要把省份id添加到url地址的最後面即可。比如蘇州的id是116,那麼想知道蘇州下有哪些縣和區的時候,訪問地址:http://guolin.tech/api/china/16/116。如此類推。

     本app使用DataSupport這款開源的數據庫框架進行城市查詢,需要在app下的build.gradle導入:

implementation 'org.litepal.android:core:1.4.1'

在清單文件中的application節點中加入:

android:name="org.litepal.LitePalApplication"

此外還需要在assets目錄下新建litepal.xml,構建名爲weather_db的數據庫,分別構建Province、City、County三張表。

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="weather_db"></dbname>
    <version value="1"></version>

    <list>
        <mapping class="db.Province"/>
        <mapping class="db.City"/>
        <mapping class="db.County"/>
    </list>
</litepal>

對於省份、城市、區或縣進行數據庫查詢,則這些實體類需要繼承自DataSupport:

package db;

import org.litepal.crud.DataSupport;

public class City extends DataSupport {

    private int id;
    private String cityName;
    private int cityCode;
    private int provinceId;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public int getCityCode() {
        return cityCode;
    }

    public void setCityCode(int cityCode) {
        this.cityCode = cityCode;
    }

    public int getProvinceId() {
        return provinceId;
    }

    public void setProvinceId(int provinceId) {
        this.provinceId = provinceId;
    }
}
package db;

import org.litepal.crud.DataSupport;

public class County extends DataSupport {
    private int id;
    private String countyName;
    private String weatherId;

    public String getWeatherId() {
        return weatherId;
    }

    public void setWeatherId(String weatherId) {
        this.weatherId = weatherId;
    }

    private int cityId;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCountyName() {
        return countyName;
    }

    public void setCountyName(String countyName) {
        this.countyName = countyName;
    }
    
    public int getCityId() {
        return cityId;
    }

    public void setCityId(int cityId) {
        this.cityId = cityId;
    }
}
package db;

import org.litepal.crud.DataSupport;

public class Province extends DataSupport {

    private int id;
    private String provinceName;
    private int provinceCode;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProvinceName() {
        return provinceName;
    }

    public void setProvinceName(String provinceName) {
        this.provinceName = provinceName;
    }

    public int getProvinceCode() {
        return provinceCode;
    }

    public void setProvinceCode(int provinceCode) {
        this.provinceCode = provinceCode;
    }
}

 

訪問服務器,所以需要在清單文件加入訪問網絡的權限:

<uses-permission android:name="android.permission.INTERNET" />

 主程序佈局僅由一個fragment組成,該fragment的佈局由一個自定義的標題欄和一個listview組成:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/choose_are_fragment"
        android:name="mini.org.miniweather.fragment.ChooseAreaFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</FrameLayout>

 fragment的佈局choose_area.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="match_parent"
    android:orientation="vertical"
    android:background="#fff"
    android:fitsSystemWindows="true">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:textColor="#fff"
            android:layout_centerInParent="true"/>
        <ImageView
            android:id="@+id/back"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:layout_marginLeft="10dp"
            android:layout_centerVertical="true"
            android:layout_alignParentLeft="true"
            android:background="@drawable/ic_back"/>
    </RelativeLayout>

        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </ListView>

</LinearLayout>

 城市列表顯示界面ChooseAreaFragment,本文使用okhttp進行網絡請求,所以需在build.gradle添加:

implementation 'com.squareup.okhttp3:okhttp:3.4.1'

該fragment的代碼及分析如下: 

package mini.org.miniweather.fragment;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.litepal.crud.DataSupport;

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

import db.City;
import db.County;
import db.Province;
import mini.org.miniweather.MainActivity;
import mini.org.miniweather.R;
import mini.org.miniweather.WeatherActivity;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import util.HttpUtil;
import util.Utility;

public class ChooseAreaFragment extends Fragment {

    private static final int LEVEL_PROVINCE = 0;
    private static final int LEVEL_CITY = 1;
    private static final int LEVEL_COUNTY = 2;
    private List<String> dataList = new ArrayList<>();
    private ArrayAdapter<String> adapter;
    private TextView titleText;
    private ImageView backButton;
    private ListView listView;
    private ProgressDialog progressDialog;
    /**
     * 省列表
     */
    private List<Province> provinceList;
    /**
     * 城市列表
     */
    private List<City> cityList;
    /**
     * 城鎮列表
     */
    private List<County> countyList;
    /**
     * 當前等級
     */
    private int currentLevel;

    /**
     * 選中的省份
     */
    private Province selectedProvince;

    /**
     * 選中的城市
     */
    private City selectedCity;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.choose_area,container,false);
        titleText = (TextView)view.findViewById(R.id.title);
        backButton = (ImageView)view.findViewById(R.id.back);
        listView = (ListView)view.findViewById(R.id.listview);
        adapter = new ArrayAdapter<>(getContext(),android.R.layout.simple_list_item_1,dataList);
        listView.setAdapter(adapter);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        queryProvinces();
        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();
                    if (getActivity() instanceof MainActivity){
                        Intent intent = new Intent(getActivity(), WeatherActivity.class);
                        intent.putExtra("weather_id",weatherId);
                        startActivity(intent);
                        getActivity().finish();
                    }else if (getActivity() instanceof WeatherActivity){
                        WeatherActivity activity = (WeatherActivity)getActivity();
                        activity.drawerLayout.closeDrawers();
                        activity.getWeatherInfo(weatherId);
                    }

                }
            }
        });

        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (currentLevel == LEVEL_COUNTY){
                    queryCities();
                }else if (currentLevel == LEVEL_CITY){
                    queryProvinces();
                }
            }
        });
    }

    /**
     * 查詢所有的省,優先從數據庫查詢,如果沒有查到再去服務器上查詢
     */
    private void queryProvinces(){
        titleText.setText("中國");
        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");
        }
    }
    /**
     * 查詢選中省內所有的市,優先從數據庫查詢,如果沒有查詢到再去服務器上查詢。
     */
    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");
        }
    }

    /**
     * 查詢選中市內所有的縣,優先從數據庫查詢,如果沒有查詢到再去服務器上查詢。
     */
    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");
        }
    }

    /**
     * 根據傳入的地址和類型從服務器上查詢省市縣數據
     * @param address
     * @param type
     */
    private void queryFromServer(String address, final String type) {
        showProgressDialog();
        HttpUtil.sendOkhttpRequest(address, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        closeProgressDialog();
                        Toast.makeText(getContext(),"加載失敗",Toast.LENGTH_SHORT).show();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String responceText = response.body().string();
                boolean result = false;
                if ("province".equals(type)){
                    result = Utility.handleProvinceResponce(responceText);
                }else if ("city".equals(type)){
                    result = Utility.handleCityResponce(responceText,selectedProvince.getId());
                }else if ("county".equals(type)){
                    result = Utility.handleCountyResponce(responceText,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();
                            }
                        }
                    });
                }
            }
        });
    }

    /**
     * 顯示進度對話框
     */
    private void showProgressDialog() {
        if (progressDialog == null){
            progressDialog = new ProgressDialog(getActivity());
            progressDialog.setMessage("正在加載...");
            progressDialog.setCanceledOnTouchOutside(false);
        }
        progressDialog.show();
    }

    /**
     * 關閉進度對話框
     */
    private void closeProgressDialog(){
        if (progressDialog!=null){
            progressDialog.dismiss();
        }
    }
}

該fragment涉及的工具類如下:

package util;

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 util;

import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;

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

import db.City;
import db.County;
import db.Province;
import interfaces.heweather.com.interfacesmodule.bean.weather.Weather;

public class Utility {

    /**
     * 解析和返回服務器返回的省級數據
     */
    public static boolean handleProvinceResponce(String responce){
        if (!TextUtils.isEmpty(responce)){
            try {
                JSONArray allProvinces = new JSONArray(responce);
                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;
    }

    /**
     * 解析和返回服務器返回的市級數據
     */
    public static boolean handleCityResponce(String responce,int provinceId){
        if (!TextUtils.isEmpty(responce)){
            try {
                JSONArray allCities = new JSONArray(responce);
                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;
    }

    /**
     * 解析和返回服務器返回的縣級數據
     */
    public static boolean handleCountyResponce(String responce,int cityId){

        if (!TextUtils.isEmpty(responce)){
            try {
                JSONArray allCounties = new JSONArray(responce);
                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;
    }

}

 2.獲取城市天氣預報

       

      本文使用和風天氣平臺提供的天氣數據來源,關於如何使用該平臺獲得城市天氣預報情況,可以參考Android 獲取實時天氣數據,在這就不多加贅述。

      每次啓動應用時,先去檢查SharedPreference中保存鍵爲"weather"的值(即和風天氣需要獲取天氣情況的城市代碼)是否爲空,如爲空,顯示城市列表fragment即ChooseAreFragment,如不爲空,則將該值通過Intent傳遞給城市天氣預報界面WeatherActivity,並啓動該Activity。

package mini.org.miniweather;

import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.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 sharedPreferences =
                PreferenceManager.getDefaultSharedPreferences(this);
        if (sharedPreferences.getString("weather",null)!= null){
            Intent intent = new Intent(this,WeatherActivity.class);
            startActivity(intent);
            finish();
        }
    }
}

該WeatherActivity界面背景使用必應服務器提供的圖片,使用Glide三方框架加載緩存的背景圖片,代碼及分析如下:

package mini.org.miniweather;

import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.google.gson.Gson;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.List;
import interfaces.heweather.com.interfacesmodule.bean.Lang;
import interfaces.heweather.com.interfacesmodule.bean.Unit;
import interfaces.heweather.com.interfacesmodule.bean.air.now.AirNow;
import interfaces.heweather.com.interfacesmodule.bean.weather.Weather;
import interfaces.heweather.com.interfacesmodule.bean.weather.forecast.ForecastBase;
import interfaces.heweather.com.interfacesmodule.bean.weather.lifestyle.LifestyleBase;
import interfaces.heweather.com.interfacesmodule.view.HeConfig;
import interfaces.heweather.com.interfacesmodule.view.HeWeather;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import util.HttpUtil;

public class WeatherActivity extends AppCompatActivity {

    private LinearLayout forecastLayout;
    private TextView aqiText;
    private TextView degreeText;
    private TextView weatherInfoText;
    private TextView pm25Text;
    private String weatherId;
    private TextView cityText;
    private ImageView bingPicImg;
    private TextView timeText;
    private TextView weatherText;
    private TextView comfortText;
    private TextView carWashText;
    private TextView sportText;
    private Button navButton;
    public DrawerLayout drawerLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (Build.VERSION.SDK_INT >21){
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }
        setContentView(R.layout.activity_weather);
        initView();
        initWeather();
    }

    private void initWeather() {
        HeConfig.init("HE1912311406181054","045f6a9bffa44f06a72c4dc903082906");
        HeConfig.switchToFreeServerNode();

    }

    private void initView() {
        forecastLayout = (LinearLayout)findViewById(R.id.forecast_layout);
        aqiText = (TextView)findViewById(R.id.aqi_text);
        degreeText = (TextView)findViewById(R.id.degree_text);
        weatherInfoText = (TextView)findViewById(R.id.weather_info_text);
        pm25Text = (TextView)findViewById(R.id.pm25_text);
        cityText = (TextView)findViewById(R.id.title_city);
        bingPicImg = (ImageView)findViewById(R.id.bing_pic);
        timeText = (TextView)findViewById(R.id.title_time);
        comfortText = (TextView)findViewById(R.id.comfort_text);
        carWashText = (TextView)findViewById(R.id.car_wash_text);
        sportText = (TextView)findViewById(R.id.sport_text);
        navButton = (Button)findViewById(R.id.nav_button);
        drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        String bingPic = prefs.getString("bing_pic", null);
        if (bingPic != null) {
            Glide.with(this).load(bingPic).into(bingPicImg);
        } else {
            loadBingPic();
        }
        weatherId = prefs.getString("weather",null);
        if (weatherId == null){
            weatherId  = getIntent().getStringExtra("weather_id");
        }
        getWeatherInfo(weatherId);
        navButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawerLayout.openDrawer(GravityCompat.START);
            }
        });
    }

    /**
     * 加載必應每日一圖
     */
    private void loadBingPic() {
        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 = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();
                editor.putString("bing_pic", bingPic);
                editor.apply();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Glide.with(WeatherActivity.this).load(bingPic).into(bingPicImg);
                    }
                });
            }

            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 獲取城市天氣預報
     * @param weatherid 城市代碼
     */
    public void getWeatherInfo(final String weatherid) {
        weatherId = weatherid;
        HeWeather.getWeather(WeatherActivity.this, weatherId,
                Lang.CHINESE_SIMPLIFIED, Unit.METRIC, new HeWeather.OnResultWeatherDataListBeansListener() {
                    @Override
                    public void onError(Throwable throwable) {

                    }

                    @Override
                    public void onSuccess(Weather weather) {
                        Log.d("hdj", "status: " + weather.getStatus());
                        if (weather != null && "ok".equals(weather.getStatus())){
                            SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit();
                            editor.putString("weather", weatherid);
                            editor.apply();
                            showWeatherInfo(weather);
                        }else{
                            Toast.makeText(WeatherActivity.this,"無法獲得該區域的天氣情況"
                                    ,Toast.LENGTH_LONG).show();
                        }

                    }
                });
        HeWeather.getAirNow(WeatherActivity.this, weatherId,
                Lang.CHINESE_SIMPLIFIED, Unit.METRIC, new HeWeather.OnResultAirNowBeansListener() {
                    @Override
                    public void onError(Throwable throwable) {

                    }
                    @Override
                    public void onSuccess(AirNow airNow) {
                        showAirInfo(airNow);
                    }
                });

    }

    /**
     * 處理並展示Weather實體類中的數據。
     */
    private void showWeatherInfo(Weather weather){
        String cityName = weather.getBasic().getLocation();
        String titleTime = weather.getUpdate().getLoc().split(" ")[1];
        int hour = Integer.parseInt(titleTime.split(":")[0]);
        boolean isDayTime = hour>=6&&hour<=18 ? true:false;
        String weatherInfo = weather.getNow().getCond_txt();
        String degreeInfo = weather.getNow().getTmp()+ "℃";
        cityText.setText(cityName);
        timeText.setText(titleTime);
        weatherInfoText.setText(weatherInfo);
        degreeText.setText(degreeInfo);
        forecastLayout.removeAllViews();
        for (ForecastBase forecast: weather.getDaily_forecast()) {
            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_info);
            TextView minText = (TextView) view.findViewById(R.id.min_info);
            dateText.setText(forecast.getDate());
            if (isDayTime) {
                infoText.setText(forecast.getCond_txt_d());
            }else{
                infoText.setText(forecast.getCond_txt_n());
            }
            maxText.setText(forecast.getTmp_max()+"℃");
            minText.setText(forecast.getTmp_min()+"℃");
            forecastLayout.addView(view);
        }
        List<LifestyleBase> lifestyleBases = weather.getLifestyle();

        comfortText.setText("舒適度:" +lifestyleBases.get(0).getTxt());
        carWashText.setText("洗車指數:" + lifestyleBases.get(6).getTxt());
        sportText.setText("出行建議:" + lifestyleBases.get(3).getTxt());
    }

    /**
     * 顯示空氣質量
     * @param airNow
     */
    private void showAirInfo(AirNow airNow){
        String airStatus = airNow.getStatus();
        if (airStatus.equals("ok")){
            String jsonData = new Gson().toJson(airNow.getAir_now_city());
            JSONObject objectAir = null;
            try {
                objectAir = new JSONObject(jsonData);
                String aqi = objectAir.getString("aqi");
                String pm25 = objectAir.getString("pm25");
                aqiText.setText(aqi);
                pm25Text.setText(pm25);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }else {
            aqiText.setText("無");
            pm25Text.setText("無");
        }
    }

}

app的build.gradle中需要導入:

 implementation 'com.github.bumptech.glide:glide:3.7.0'

以上就是整個app的具體介紹,具體思路大概是先通過DataSupport獲取遠程服務器上的城市列表,然後通過和風天氣平臺獲取選中的城市天氣預報及空氣質量指數等。

最後附上WeatherActivity的相關佈局文件代碼:

activity_weather:

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

    <ImageView
        android:id="@+id/bing_pic"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ScrollView
            android:id="@+id/weather_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="none"
            android:overScrollMode="never">

            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fitsSystemWindows="true">
                <include layout="@layout/title"/>
                <include layout="@layout/now"/>
                <include layout="@layout/forecast"/>
                <include layout="@layout/aqi" />
                <include layout="@layout/suggestion"/>

            </LinearLayout>
        </ScrollView>
        <fragment
            android:id="@+id/choose_are_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:name="mini.org.miniweather.fragment.ChooseAreaFragment"
            />


    </android.support.v4.widget.DrawerLayout>

</FrameLayout>

title.xml:

<?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="match_parent">

    <Button
        android:id="@+id/nav_button"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginLeft="10dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:background="@drawable/ic_home"/>

    <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"/>

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

</RelativeLayout>

now.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:orientation="vertical"
    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:textSize="20sp"
        android:textColor="#fff"/>

</LinearLayout>

forecast.xml:

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

    <TextView
        android:layout_marginLeft="15dp"
        android:layout_marginTop="15dp"
        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>

 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="match_parent"
    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:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/info_text"
        android:layout_weight="1"
        android:layout_gravity="center_vertical"
        android:gravity="center"
        android:textColor="#fff"/>

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

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

</LinearLayout>

 aqi.xml:

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

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

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

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1">
            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true">

                <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:text="AQI指數"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:textColor="#fff"/>

            </LinearLayout>


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

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

                <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:text="PM2.5指數"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:textColor="#fff"/>

            </LinearLayout>


        </RelativeLayout>
    </LinearLayout>

</LinearLayout>

suggestion.xml:

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

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

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

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

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

</LinearLayout>

:本文參考自歐酷天氣開源項目。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章