第一篇博客 ——天气的小情绪
First.创建数据库和表
在com.example.coolweather添加几个包,db包用于存放数据库模型相关的代码,gson包用于存放GSON模型相关的代码,service用于存放服务相关的代码,util包用于存放工具相关的代码。
1.编辑app/build.gradle文件,在dependcies闭包中添加如下内容
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12
implementation 'org.litepal.android:core:1.4.1'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
implementation 'com.google.code.gson:gson:2.7'
implementation 'com.github.bumptech.glide:glide:3.7.0'
2.在db包建Province类
package com.example.coolweather.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;
}
}
在db包建City类
package com.example.coolweather.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 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;
}
}
在db包建County类
package com.example.coolweather.db;
import org.litepal.crud.DataSupport;
public class County extends DataSupport {
private int id;
private String countyName;
private String weatherId;
private int cityId;
public void setId(int id){
this.id=id;
}
public String getCountyName(){
return countyName;
}
public void setCountyName(String countyName) {
this.countyName = countyName;
}
public String getWeatherId(){
return weatherId;
}
public void setWeatherId(String weatherId){
this.weatherId=weatherId;
}
public int getCityId(){
return cityId;
}
public void setCityId(int cityId){
this.cityId=cityId;
}
}
3.配置litepal.xml文件。右击app/src/main目录—>New->Directory,创建一个assets目录,然后在assets目录下新建一个litepal.xml文件,接着编辑litepal.xml中的内容。
<litepal>
<dbname value="cool_weather" />
<version value="1" />
<list>
<mapping class="com.example.coolweather.db.Province" />
<mapping class="com.example.coolweather.db.City" />
<mapping class="com.example.coolweather.db.County" />
</list>
</litepal>
4.修改AndroidManifest.xml中的代码
<application
android:name="org.litepal.LitePalApplication"
android:allowBackup="true"
Second.遍历全国省市县数据
1.在util包下增加一个HttpUtil类
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);
}
}
2.在util包下新建一个Utility类
public class Utility {
/**
* 解析和处理服务器返回的省级数据
*/
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;
}
/**
* 解析和处理服务器返回的市级数据
*/
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;
}
/**
* 解析和处理服务器返回的县级数据
*/
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;
}
3.在res/layout目录中新建choose_area.xml布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary">
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#fff"
android:textSize="20sp" />
<Button
android:id="@+id/back_button"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@drawable/back" />
</RelativeLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
4.编写用于遍历省市县数据碎片。新建AreaFragment继承自Fragment
public class AreaFragment 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 ArrayAdapter<String> adapter;
private TextView titleText;
private Button backButton;
private ListView listView;
private List<String> datalist = new ArrayList<>();
/**
* 省列表
*/
private List<Province> provinceList;
/**
* 市列表
*/
private List<City> cityList;
/**
* 县列表
*/
private List<County> countyList;
/**
* 选中的省份
*/
private Province selectedProvince;
/**
* 选中的城市
*/
private City selectedCity;
/**
* 当前选中的级别
*/
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();
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.swipeRefresh.setRefreshing(true);
activity.requestWeather(weatherId);
}
}
}
});
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (currentLevel == LEVEL_COUNTY) {
queryCities();
} else if (currentLevel == LEVEL_CITY) {
queryProvinces();
}
}
});
queryProvinces();
}
/**
* 查询全国所有的省,优先从数据库查询,如果没有查询到再去服务器上查询
*/
private void queryProvinces() {
titleText.setText("中国");
backButton.setVisibility(View.GONE);
provinceList = DataSupport.findAll(Province.class);
if (provinceList.size() > 0) {
Log.e(TAG,"------------"+provinceList.size());
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");
}
}
/**
* 根据传入的地址和类型从服务器上查询省市县数据
*/
private void queryFromServer(String address, final String type) {
Log.e(TAG, "queryFromServer: " + address);
showProgressDialog();
HttpUtil.sendOkHttpRequest(address, new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseText = response.body().string();
Log.e(TAG,responseText+"---------" + type);
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) {
Log.e(TAG,"--------"+e.toString());
//通过runOnUiThread()方法回到主线程处理逻辑
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(getContext(), "加载失败", Toast.LENGTH_SHORT).show();
}
});
}
});
}
/**
* 显示进程对话框
*/
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();
}
}
}
5.修改activity_main.xml中的代码
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/choose_area_fragment"
android:name="com.example.coolweather.util.AreaFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
6.修改res/values/styles.xml中的代码
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
然后可以看到所有省级,市级,县级的数据显示出来了
Third显示天气信息
1.定义GSON实体类
在gson包下建立一个Basic类
public class Basic {
@SerializedName("city")
public String cityName;
@SerializedName("id")
public String weatherId;
public Update update;
public class Update{
@SerializedName("loc")
public String updateTime;
}
}
在gson包新建一个AQI类
public class AQI {
public AQICity city;
public class AQICity{
public String aqi;
public String pm25;
}
}
在gson包新建一个Now类
public class Now {
@SerializedName("tmp")
public String temperatrue;
@SerializedName("cond")
public More more;
public class More{
@SerializedName("txt")
public String info;
}
}
在gson包中新建一个Suggestion类
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;
}
}
在gson包新建一个Forecast类
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;
}
}
在gson包新建一个Weather类
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。编写天气界面
首先创建一个用于显示天气的活动。右击com.example.coolweather->New->Activity->Empty Activity,创建一个WeatherActivity,并将布局名指定成activity_weather.xml。
1.右击res/layout—>New->Layout resource file,新建一个title.xml作为头布局
<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_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textColor="#fff"
android:textSize="16sp"/>
</RelativeLayout>
新建一个now.xml作为当前天气信息的布局
<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>
新建forecast.xml作为未来几天天气信息的布局
<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:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
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文件,定义一个未来天气信息的子项布局
<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="right"
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>
新建suggestion.xml作为生活建议信息的布局
<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:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:text="生活建议"
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.这样我们就把天气界面上的每个部分布局就编写好了,接下来的工作就是将他们引入到activity_weather.xml当中
<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: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>
</FrameLayout>
3.将天气显示到界面上
首先在Utility类中添加一个用于解析天气JSON数据的方法
/**
* 将返回的JSON数据解析成Weather实体类
*/
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;
}
}
接下来的工作是如何在活动中去请求天气数据,以及将数据展示到界面上。修改WeatherActivity中的代码·
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);
//初始化各控件
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);
String weatherString=prefs.getString("weather",null);
if (weatherString!=null){
//有缓存时直接解析天气数据
Weather weather= Utility.handleWeatherResponse(weatherString);
mWeatherId=weather.basic.weatherId;
showWeatherInfo(weather);
}else {
//无缓存时服务器查询天气
mWeatherId=getIntent().getStringExtra("weather_id");
weatherLayout.setVisibility(View.INVISIBLE);
requestWeather(mWeatherId);
}
/**
* 根据天气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 onFailure(Call call, IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(WeatherActivity.this,"获取天气信息失败",
Toast.LENGTH_SHORT).show();
swipeRefresh.setRefreshing(false);
}
});
}
/**
* 处理并展示Weather实体类中的数据
*/
private void showWeatherInfo(Weather weather){
String cityName=weather.basic.cityName;
String updateTime=weather.basic.update.updateTime.split(" ")[1];
String degree=weather.now.temperatrue+"℃";
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="舒适度:"+weather.suggestion.comfort.info ;
String carWash="洗车指数:"+weather.suggestion.carWash.info;
String sport="运动建议:"+weather.suggestion.sport.info;
comfortText.setText(comfort);
carWashText.setText(carWash);
sportText.setText(sport);
weatherLayout.setVisibility(View.VISIBLE);
Intent intent=new Intent(this, AntoUpdateService.class);
startService(intent);
}
}
接下来要做的就是如何从省市县列表界面跳转到天气界面,修改AreaFragment中的代码
@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();
if(getActivity()instanceof MainActivity){
Intent intent=new Intent(getActivity(), WeatherActivity.class);
intent.putExtra("weather_id",weatherId);
startActivity(intent);
getActivity().finish();
}
还需要在MainActivity中加入一个缓存数据的判断才行,修改MainActivity中的代码
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();
}
}
}
然后我们就可以下滑查天气了
Fourth.获取必应每日一图
必应每日一图的接口:http://guolin.tech/api/bing_pic
1.首先修改activity_weather.xml中的代码
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
<ImageView
android:id="@+id/bing_pic_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
接着修改WeatherActivity中的代码
private ImageView bingPicImg;
//初始化各控件
bingPicImg=(ImageView)findViewById(R.id.bing_pic_img);
。。。。。。
String bingPic=prefs.getString("bing_pic",null);
if(bingPic!=null){
Glide.with(this).load(bingPic).into(bingPicImg);
}else{
loadBingPic();
}
/**
* 根据天气id请求城市天气信息
*/
public void requestWeather(final String weatherId){
。。。。。。
loadBingPic();
}
/**
* 加载成功每日一图
*/
private void loadBingPic(){
String requestBingPic="http://guolin.tech/api/bing_pic";
HttpUtil.sendOkHttpRequest(requestBingPic, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@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);
}
});
}
});
}
2.实现背景图与状态栏融合到一起的效果
@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);
在ScrollView的LinearLayout中增加android:fitsSystemWindows属性,设置成true就表示会为系统状态栏留出空间
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
。。。。。。
Fifth.手动更新天气和城市
1.首先修改activity_weather.xml中的代码
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
。。。。。
</android.support.v4.widget.SwipeRefreshLayout>
然后修改WeatherActivity中的代码,加入更新天气的处理逻辑
private Button navButton;
public SwipeRefreshLayout swipeRefresh;
。。。。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
。。。。。。
swipeRefresh=(SwipeRefreshLayout)findViewById(R.id.swipe_refresh);
swipeRefresh.setColorSchemeResources(R.color.colorPrimary);
SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(this);
String weatherString=prefs.getString("weather",null);
if (weatherString!=null){
//有缓存时直接解析天气数据
Weather weather= Utility.handleWeatherResponse(weatherString);
mWeatherId=weather.basic.weatherId;
showWeatherInfo(weather);
}else {
//无缓存时服务器查询天气
mWeatherId=getIntent().getStringExtra("weather_id");
weatherLayout.setVisibility(View.INVISIBLE);
requestWeather(mWeatherId);
}
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
requestWeather(mWeatherId);
}
});
String bingPic=prefs.getString("bing_pic",null);
if(bingPic!=null){
Glide.with(this).load(bingPic).into(bingPicImg);
}else{
loadBingPic();
}
/**
* 根据天气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 onFailure(Call call, IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(WeatherActivity.this,"获取天气信息失败",
Toast.LENGTH_SHORT).show();
**swipeRefresh.setRefreshing(false);**
}
});
}
@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();
**mWeatherId=weather.basic.weatherId;**
showWeatherInfo(weather);
}else {
Toast.makeText(WeatherActivity.this, "获取天气信息失败",
Toast.LENGTH_SHORT).show();
}
**swipeRefresh.setRefreshing(false);**
}
});
}
});
loadBingPic();
}
2.切换城市
修改title.xml中的代码
<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/house" />
接着修改activity_weather.xml布局加入滑动菜单功能
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
。。。。。
<fragment
android:id="@+id/choose_area_fragment"
android:name="com.example.coolweather.util.AreaFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
接下来需要在滑动菜单中加入处理逻辑,修改WeatherActivity中的代码
public DrawerLayout drawerLayout;
private Button navButton;
。。。。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
。。。。。
navButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
drawerLayout.openDrawer(GravityCompat.START);
}
});
修改AreaFragment的代码
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.swipeRefresh.setRefreshing(true);
activity.requestWeather(weatherId);
}**
Sixth.修改图标和名称
事先准备好一张图片作为软件图标,放入到所有以mipmap开头的目录下,然后修改AndroidMannifest.xml中的代码
<application
android:name="org.litepal.LitePalApplication"
android:allowBackup="true"
android:icon="@mipmap/forecast1"
android:label="@string/app_name"
然后修改一下程序的名称,打开res/values/string.xml文件,
<resources>
<string name="app_name">天空的小情绪</string>
</resources>