<第二行代码>中的天气应用
来源:互联网 发布:软件盒子网站 编辑:程序博客网 时间:2024/05/21 15:45
<第二行代码>中的天气应用(1)--文件结构和LitePal
====文件结构是这样的
db文件夹中存放数据库模型相关代码,每个类对应数据库中的表
gson文件夹中存放GSON模型相关代码,每个类对应服务器响应数据
service存放服务相关代码,后台自动更新类
util存放工具相关代码,发送请求类和处理响应的类
====添加依赖库
compile 'org.litepal.android:core:1.4.1' //LitePal用于对数据库操作
compile 'com.squareup.okhttp3:okhttp:3.4.1' //OkHttp用于发送网络请求
compile 'com.google.code.gson:gson:2.7' //GSON用于解析JSON数据
compile 'com.github.bumptech.glide:glide:3.7.0' //Glide用于加载和展示图片
====配置文件
<uses-permissionandroid:name="android.permission.INTERNET"/> //添加网络权限
android:name="org.litepal.LitePalApplication"//配置LietPal
android:icon="@mipmap/logo" //更改应用logo
====创建省类
LitePal是对象关系数据库,所以要创建继承DataSupport的类来模拟表
package com.scx040407.myweather.db;
import org.litepal.crud.DataSupport;
/**
* Created by Administrator on 2017/5/70007.
* 实体类,对应数据库中的表province
* 格式是这样的[{"id":"1","name":"北京"},{...}]
*/
public class Provinceextends DataSupport {
private int id; //每个实体类中都应该有的字段
private StringprovinceName;//省名 北京
private int provinceCode;//省代号 1
public int getId() {
return id;
}
public void setId(intid) {
this.id= id;
}
public StringgetProvinceName() {
return provinceName;
}
public void setProvinceName(StringprovinceName) {
this.provinceName= provinceName;
}
public int getProvinceCode(){
return provinceCode;
}
public void setProvinceCode(intprovinceCode) {
this.provinceCode= provinceCode;
}
}
====创建市类
package com.scx040407.myweather.db;
import org.litepal.crud.DataSupport;
/**
* Created by Administrator on 2017/5/70007.
* 实体类,对应数据库中的表city
* 格式是这样的[{"id":"116","name":"苏州"},{...}]
*/
public class Cityextends DataSupport {
private int id;
private StringcityName;
private int cityCode;
private int provinceId;
public int getId() {
return id;
}
public void setId(intid) {
this.id= id;
}
public StringgetCityName() {
return cityName;
}
public void setCityName(StringcityName) {
this.cityName= cityName;
}
public int getCityCode() {
return cityCode;
}
public void setCityCode(intcityCode) {
this.cityCode= cityCode;
}
public int getProvinceId(){
return provinceId;
}
public void setProvinceId(intprovinceId) {
this.provinceId= provinceId;
}
}
====创建区县类
package com.scx040407.myweather.db;
import org.litepal.crud.DataSupport;
/**
* Created by Administrator on 2017/5/70007.
* 实体类,对应数据库中的表county
* 格式是这样的[{"id":"942","name":"吴江","weather_id":"CN1001190407"},{...}]
*/
public class Countyextends DataSupport {
private int id;
private StringcountyName;
private StringweatherId;
private int cityId;
public int getCityId() {
return cityId;
}
public void setCityId(intcityId) {
this.cityId= cityId;
}
public StringgetWeatherId() {
return weatherId;
}
public void setWeatherId(StringweatherId) {
this.weatherId= weatherId;
}
public StringgetCountyName() {
return countyName;
}
public void setCountyName(StringcountyName) {
this.countyName= countyName;
}
public int getId() {
return id;
}
public void setId(intid) {
this.id= id;
}
}
<第二行代码>中的天气应用(2)--GSON
====天气基本信息Basic类
本类用于帮助GSON解析天气,天气的返回数据是如下这样的,
吴江区县的天气信息:
{"HeWeather": [{"aqi":{"city":{"aqi":"64","pm10":"78","pm25":"43","qlty":"良"}},"basic":{"city":"吴江","cnty":"中国","id":"CN101190407","lat":"31.16040421","lon":"120.64160156","update":{"loc":"2017-05-11 22:53","utc":"2017-05-11 14:53"}},"daily_forecast":[{"astro":{"mr":"19:01","ms":"05:26","sr":"05:05","ss":"18:44"},"cond":{"code_d":"100","code_n":"307","txt_d":"晴","txt_n":"大雨"},"date":"2017-05-11","hum":"60","pcpn":"0.7","pop":"93","pres":"1012","tmp":{"max":"32","min":"22"},"uv":"10","vis":"14","wind":{"deg":"204","dir":"南风","sc":"微风","spd":"3"}},{"astro":{"mr":"19:53","ms":"06:04","sr":"05:04","ss":"18:44"},"cond":{"code_d":"306","code_n":"101","txt_d":"中雨","txt_n":"多云"},"date":"2017-05-12","hum":"75","pcpn":"31.2","pop":"100","pres":"1010","tmp":{"max":"22","min":"17"},"uv":"3","vis":"15","wind":{"deg":"63","dir":"东北风","sc":"4-5","spd":"18"}},{"astro":{"mr":"20:44","ms":"06:44","sr":"05:04","ss":"18:45"},"cond":{"code_d":"100","code_n":"101","txt_d":"晴","txt_n":"多云"},"date":"2017-05-13","hum":"66","pcpn":"0.0","pop":"9","pres":"1009","tmp":{"max":"29","min":"19"},"uv":"10","vis":"20","wind":{"deg":"190","dir":"西南风","sc":"微风","spd":"5"}}],"hourly_forecast":[],"now":{"cond":{"code":"104","txt":"阴"},"fl":"29","hum":"82","pcpn":"0","pres":"1010","tmp":"22","vis":"7","wind":{"deg":"117","dir":"西北风","sc":"3-4","spd":"11"}},"status":"ok","suggestion":{"air":{"brf":"中","txt":"气象条件对空气污染物稀释、扩散和清除无明显影响,易感人群应适当减少室外活动时间。"},"comf":{"brf":"较不舒适","txt":"白天天气晴好,明媚的阳光在给您带来好心情的同时,也会使您感到有些热,不很舒适。"},"cw":{"brf":"不宜","txt":"不宜洗车,未来24小时内有雨,如果在此期间洗车,雨水和路上的泥水可能会再次弄脏您的爱车。"},"drsg":{"brf":"热","txt":"天气热,建议着短裙、短裤、短薄外套、T恤等夏季服装。"},"flu":{"brf":"少发","txt":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。"},"sport":{"brf":"较不宜","txt":"天气较好,无雨水困扰,但考虑气温很高,请注意适当减少运动时间并降低运动强度,运动后及时补充水分。"},"trav":{"brf":"适宜","txt":"天气较好,但丝毫不会影响您的心情。微风,虽天气稍热,却仍适宜旅游,不要错过机会呦!"},"uv":{"brf":"弱","txt":"紫外线强度较弱,建议出门前涂擦SPF在12-15之间、PA+的防晒护肤品。"}}}]}
要解析这么多的内容使用JSON显然很麻烦,所以用GSON,直接建立对应的类比较方便.
我们在上面的信息中挑选一些有用的出来.标记成红色的是我们要创建对应的类.最后汇总到weather类中
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. * 本类的格式对应的是返回数据的格式, * 本类中basic中有用的内容格式如下: *"basic":{ * "city":"苏州", * "id":"CN101190401", * "update":{ * "loc":"2016-08-08 21:58" * } *} * * */public class Basic { //模仿对应的格式定义变量,创建类就可以了,这是GSON解析的准备工作 @SerializedName("city") //注解,就是改名字的意思 public String cityName; @SerializedName("id") public String weatherId; public Update update; public class Update{ @SerializedName("loc") public String updateTime; }}
====天气AQI类,Now类,Suggestion类,daily_forecast类(实际是Forecast类,单个的预报,然后在weather类中声明成List就可以了)
package com.scx040407.myweather.gson;/** * Created by Administrator on 2017/5/8 0008. */public class AQI { public AQICity city; public class AQICity{ public String aqi; public String pm25; }}
-----------------------------------------------------------------------------------------
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. */public class Now { @SerializedName("tmp") public String temperature; @SerializedName("cond") public More more; public class More{ @SerializedName("txt") public String info; }}
-----------------------------------------------------------------------------------------
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. */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; }}
-----------------------------------------------------------------------------------------
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;/** * Created by Administrator on 2017/5/8 0008. * */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; }}
-----------------------------------------------------------------------------------------
package com.scx040407.myweather.gson;import com.google.gson.annotations.SerializedName;import java.util.List;/** * Created by Administrator on 2017/5/8 0008. * 本类对应的是 * { * "HeWeather":[ * { * "status":"ok", * "basic":{}, * "aqi":{}, * "now":{}, * "suggestion":{}, * "daily_forecast":[] * } * ] * } * 返回数据的汇总,老规矩,按照一定格式对应写就行 * * 所有的GSON都定义好了,准备工作完成了,就可以开始解析了 * */public class Weather { public String status; public Basic basic; public AQI aqi; public Now now; public Suggestion suggestion; @SerializedName("daily_forecast") //这个有点特殊,天气类返回的是数组多日的天气,我们定义 // 的类是单日的天气类,所以用List来进行声明 public List<Forecast> forecastList;}
关于GSON的用法我的感觉就是创建对应的类,格式对应,名字对应.只要创建好了,再写一行代码命令开始解析,数据就会自动被添加到对应的类中,想取出来就使用对象进行调用即可.
<第二行代码>中的天气应用(3)--工具类OKhttp和JSON解析
发送网络请求的工具类:
回调接口中重写的方法主要是用来处理响应的.
package com.scx040407.myweather.util;import okhttp3.OkHttpClient;import okhttp3.Request;/** * Created by Administrator on 2017/5/7 0007. * 用来发送请求的类 */public class HttpUtil { //发送请求的类,传入两个参数,第一个是url.第二个是回调接口,传参时需要重写方法onResponse和onFailure 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); }}
-------------------------------------------------------------------------------------------------------
省,市,区县的数据比较简单,所以用JSON来解析即可.数据格式分别如下:
请求http://guolin.tech/api/china返回的数据(省):
[{"id":1,"name":"北京"},{"id":2,"name":"上海"},{"id":3,"name":"天津"},{"id":4,"name":"重庆"},{"id":5,"name":"香港"},{"id":6,"name":"澳门"},{"id":7,"name":"台湾"},{"id":8,"name":"黑龙江"},{"id":9,"name":"吉林"},{"id":10,"name":"辽宁"},{"id":11,"name":"内蒙古"},{"id":12,"name":"河北"},{"id":13,"name":"河南"},{"id":14,"name":"山西"},{"id":15,"name":"山东"},{"id":16,"name":"江苏"},{"id":17,"name":"浙江"},{"id":18,"name":"福建"},{"id":19,"name":"江西"},{"id":20,"name":"安徽"},{"id":21,"name":"湖北"},{"id":22,"name":"湖南"},{"id":23,"name":"广东"},{"id":24,"name":"广西"},{"id":25,"name":"海南"},{"id":26,"name":"贵州"},{"id":27,"name":"云南"},{"id":28,"name":"四川"},{"id":29,"name":"西藏"},{"id":30,"name":"陕西"},{"id":31,"name":"宁夏"},{"id":32,"name":"甘肃"},{"id":33,"name":"青海"},{"id":34,"name":"新疆"}]
请求http://guolin.tech/api/china/16返回的数据(市):
[{"id":113,"name":"南京"},{"id":114,"name":"无锡"},{"id":115,"name":"镇江"},{"id":116,"name":"苏州"},{"id":117,"name":"南通"},{"id":118,"name":"扬州"},{"id":119,"name":"盐城"},{"id":120,"name":"徐州"},{"id":121,"name":"淮安"},{"id":122,"name":"连云港"},{"id":123,"name":"常州"},{"id":124,"name":"泰州"},{"id":125,"name":"宿迁"}]
请求http://guolin.tech/api/china/16/116返回的数据(区县):
[{"id":937,"name":"苏州","weather_id":"CN101190401"},{"id":938,"name":"常熟","weather_id":"CN101190402"},{"id":939,"name":"张家港","weather_id":"CN101190403"},{"id":940,"name":"昆山","weather_id":"CN101190404"},{"id":941,"name":"吴中","weather_id":"CN101190405"},{"id":942,"name":"吴江","weather_id":"CN101190407"},{"id":943,"name":"太仓","weather_id":"CN101190408"}]
都有name和id,但是区县多了一个weather_id字段,以吴江为例,要先拿到CN101190407才能去天气接口请求数据.
-----------------------------------------------------------------------------------------------------
package com.scx040407.myweather.util;import android.text.TextUtils;import com.google.gson.Gson;import com.scx040407.myweather.db.City;import com.scx040407.myweather.db.County;import com.scx040407.myweather.db.Province;import com.scx040407.myweather.gson.Weather;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;/** * Created by Administrator on 2017/5/7 0007. * 用来解析响应的类.分为 省响应,市响应,县(天气)响应 * 省所要解析的数据格式是这样的: [{"id":1,"name":"北京"},······] */public class Utility {
//想要使用这里面的方法就要先把响应解析成字符串,当做参数传入
public static boolean handleProvinceResponse(String response){ if(!TextUtils.isEmpty(response)){ //判断response是否为空,返回true或false try { JSONArray allProvinces=new JSONArray(response); for (int i=0; i<allProvinces.length(); i++){ //遍历所有省 JSONObject provinceObject=allProvinces.getJSONObject(i); //拿到JSON对象 Province province=new Province(); //新建province实例 province.setProvinceName(provinceObject.getString("name"));//设置名字 北京 province.setProvinceCode(provinceObject.getInt("id"));//设置省代号 1 province.save(); //因为继承了DataSupport,所以这个方法的意思是将 名字和省代号存储进数据库的省表中 } return true; } catch (JSONException e) { e.printStackTrace(); } } return false; } public static boolean handleCityResponse(String response,int provinceId){ if(!TextUtils.isEmpty(response)){ //判断response是否为空,返回true或false try { JSONArray allCities=new JSONArray(response); for (int i=0; i<allCities.length(); i++){ //遍历所有市 JSONObject cityObject=allCities.getJSONObject(i); //拿到JSON对象 City city=new City(); //新建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)){ //判断response是否为空,返回true或false try { JSONArray allCounties=new JSONArray(response); for (int i=0; i<allCounties.length(); i++){ //遍历所有省 JSONObject countyObject=allCounties.getJSONObject(i); //拿到JSON对象 County county=new County(); //新建区县实例 county.setCountyName(countyObject.getString("name"));//设置区县名字 county.setWeatherId(countyObject.getString("weather_id"));//设置天气id county.setCityId(cityId);//设置所属市的名字,直接从方法的参数里面获取 county.save(); //将区县名字,天气id,所属市名字存储进数据库的县表中 } return true; } catch (JSONException e) { e.printStackTrace(); } } return false; } public static Weather handleWeatherResponse(String response){ try { JSONObject jsonObject=new JSONObject(response);//JSONObject解析花括号{} JSONArray jsonArray=jsonObject.getJSONArray("HeWeather");//JSONArray解析方括号[] String weatherContent=jsonArray.getJSONObject(0).toString();//转换成字符串,相互转换的方法貌似都很重要 return new Gson().fromJson(weatherContent
,Weather.class);//调用fromJson方法把字符串按照Weather类进行解析
} catch (JSONException e) { e.printStackTrace(); } return null; }}
<第二行代码>中的天气应用(4)--省市县列表碎片和MainActivity(难)
碎片类是干什么的?
是加载省市县列表的.第一次使用即没有缓存数据的时候,先提供省列表,用户点击后提供点击省的市列表,点击市再提供县列表,再点击则跳转到天气活动.如果不是第一次使用即有缓存数据的时候,碎片隐藏在屏幕左边的滑动菜单中.
为什么要用到碎片呢?
因为复用方便.有两处用到它的地方:第一处是第一次登录没有缓存信息的时候,碎片直接展示给用户.第二处是天气活动中的滑动菜单.如果两处的代码都写的话会很麻烦,而且容易出错.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
碎片的布局是这样的:
choose_area.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="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:textColor="#fff"
android:textSize="20sp"
android:layout_centerInParent="true"/>
<Button
android:id="@+id/back_button"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_back"
/>
</RelativeLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
碎片类是这样的:
package com.scx040407.myweather;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
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.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.scx040407.myweather.db.City;
import com.scx040407.myweather.db.County;
import com.scx040407.myweather.db.Province;
import com.scx040407.myweather.util.HttpUtil;
import com.scx040407.myweather.util.Utility;
import org.litepal.crud.DataSupport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
/**
* Created by Administrator on 2017/5/70007.
* 碎片的生命周期:
1.onAttach() 当碎片和活动建立关联的时候调用。
2.onCreateView() 为碎片创建视图(加载布局)时调用。
3.onActivityCreated() 确保与碎片相关联的活动一定已经创建完毕的时候调用。
4.onDestroyView() 当与碎片关联的视图被移除的时候调用。
5.onDetach() 当碎片和活动解除关联的时候调用。
*/
public class ChooseAreaFragmentextends Fragment{
publicstatic final int LEVEL_PROVINCE=0;
publicstatic final int LEVEL_CITY=1;
publicstatic final int LEVEL_COUNTY=2;
private ProgressDialogprogressDialog;
private TextViewtitleText;
private ButtonbackButton;
private ListViewlistView;
private ArrayAdapter<String>adapter;
private List<String>dataList=newArrayList<>();//放在adapter中作为ListView的列表
private List<Province>provinceList;
private List<City>cityList;
private List<County>countyList;
private ProvinceselectedProvince;
private CityselectedCity;
privateint currentLevel;
/*
* 加载ListView
* */
@Override
//onCreateView方法在碎片加载布局时调用
public ViewonCreateView(LayoutInflater inflater, ViewGroup container,
BundlesavedInstanceState) {
Viewview=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);
//ListView的适配器,参数是:context,子项布局(内置的),List(dataList)
adapter=newArrayAdapter<>(getContext(),android.R.layout.simple_list_item_1,dataList);
listView.setAdapter(adapter);
returnview;
}
/*
* 判断,根据点击来判断该在碎片里展示的内容
* */
@Override
//onActivityCreated方法确保与碎片相关联的活动一定已经创建完毕的时候调用。
public void onActivityCreated( BundlesavedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView.setOnItemClickListener(newAdapterView.OnItemClickListener() {
@Override
//ListView的点击事件,写法要注意
public void onItemClick(AdapterView<?>parent, View view,int position, longid) {
//判断现在是哪个页面,不同的页面让列表加载不同的数据
if(currentLevel==LEVEL_PROVINCE){
//position是int数,意义是列表子项对应的序号,点击时返回被点击项的序号
// provinceList.get(position)的意思是拿到点击的那个项即省类
selectedProvince=provinceList.get(position);
queryCities();
}else if (currentLevel==LEVEL_CITY){
selectedCity=cityList.get(position);
queryCounties();
}else if (currentLevel==LEVEL_COUNTY){
//拿到可用于请求天气数据的weather_id
String weatherId=countyList.get(position).getWeatherId();
//getActivity()方法,得到和当前碎片相关联的活动,详见碎片与活动的通信
//如果是在主活动中.即主活动判断了缓存信息,为无,那么碎片就是在主活动中
//具体情况参考MainActivity类
if (getActivity()instanceof MainActivity) {
Intent intent = new Intent(getActivity(), WeatherActivity.class);
intent.putExtra("weather_id", weatherId);//把当前的县的id传过去
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(newView.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);//调用litePal的查询接口从数据库中读取省级数据
//再把得到的数据赋值给dataList,从而更新适配器,更新列表.
if (provinceList.size()>0){ //如果不是第一次请求,即从Province类中拿到了数据
dataList.clear(); //先清空列表
for (Province province :provinceList){
dataList.add(province.getProvinceName());
}
adapter.notifyDataSetChanged();//通知适配器更新
listView.setSelection(0);//设置当前选择的项,0代表第一个
currentLevel=LEVEL_PROVINCE;
}else{ //如果是第一次请求,数据库(即Province,City,County类)中没有数据
String address="http://guolin.tech/api/china"; //注意这里请求的url,省市县都不一样的
queryFromServer(address,"province");//调用从服务器中请求信息的方法
}
}
/*
* 从服务器请求数据
* */
private void queryFromServer(Stringaddress,final String type) {
showProgressDialog();
HttpUtil.sendOkHttpRequest(address,newCallback() { //发送请求从服务器获取数据,重写回调接口
//重写回调接口中的两个方法,失败和响应
@Override //如果处理失败则自动调用这个方法
public void onFailure(Call call,IOException e) {
//回到主线程处理逻辑
getActivity().runOnUiThread(newRunnable(){
@Override
public void run() {
closeProgressDialog();//调用关闭进度条方法
Toast.makeText(getContext(),"加载失败",Toast.LENGTH_SHORT).show();
}
});
}
@Override//如果收到服务器的响应则自动调用这个方法
public void onResponse(Call call, Responseresponse)throws IOException {
StringresponseText=response.body().string();
boolean result=false;//用来接收处理结果,并进行下一步判断
if ("province".equals(type)){
//调用工具类处理被转换成String形式的响应消息,响应消息作为参数传入
result= Utility.handleProvinceResponse(responseText);
}else if ("city".equals(type)){
//第二个参数是省的id,在queryCity时要用到
result= Utility.handleCityResponse(responseText,selectedProvince.getId());
}else if ("county".equals(type)){
result=Utility.handleCountyResponse(responseText,selectedCity.getId());
}
if (result){ //查询已经完毕,切换回主线程
getActivity().runOnUiThread(newRunnable(){
@Override
public void run() {
closeProgressDialog();
if ("province".equals(type)){
queryProvinces();
}else if ("city".equals(type)){
queryCities();
}else if ("county".equals(type)){
queryCounties();
}
}
});
}
}
});
}
/*
* 关闭进度条
* */
private void closeProgressDialog() {
if (progressDialog!= null){
progressDialog.dismiss();//取消掉进度条
}
}
/*
* 显示进度条
* */
private void showProgressDialog() {
if (progressDialog==null){
progressDialog=newProgressDialog(getActivity());
progressDialog.setMessage("正在加载...");
progressDialog.setCanceledOnTouchOutside(false);//设置为不可点击框外取消
}
progressDialog.show();
}
/*
* 查询区县
* */
private void queryCounties() {
titleText.setText(selectedCity.getCityName());
backButton.setVisibility(View.VISIBLE);
//条件查询语句,详见LitePal用法
countyList=DataSupport.where("cityid=?",String.valueOf(selectedCity.getId())).find(County.class);
if(countyList.size()>0){
dataList.clear();
for(Countycounty:countyList){
dataList.add(county.getCountyName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
currentLevel=LEVEL_COUNTY;
}else{
intprovinceCode=selectedProvince.getProvinceCode();
intcityCode=selectedCity.getCityCode();
//注意这里请求的url,省市县都不一样的
String address="http://guolin.tech/api/china/"+provinceCode+"/"+cityCode;
queryFromServer(address,"county");
}
}
/*
* 查询市
* */
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(Citycity:cityList){
dataList.add(city.getCityName());
}
adapter.notifyDataSetChanged();
listView.setSelection(0);
currentLevel=LEVEL_CITY;
}else{
intprovinceCode=selectedProvince.getProvinceCode();
String address="http://guolin.tech/api/china/"+provinceCode; //注意这里请求的url,省市县都不一样的
queryFromServer(address,"city");
}
}
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
activity_main.xml
<?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">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/choose_area_fragment"
android:name="com.scx040407.myweather.ChooseAreaFragment"/>
</FrameLayout>
-------------------------------------------------------------------------------------------------
主活动类
package com.scx040407.myweather;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivityextends AppCompatActivity {
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//拿到本地缓存实例
SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(this);
//判断缓存中有无信息 有就直接开启天气活动,无就什么也不做也就是显示activity_main布局中的内容即碎片
if (prefs.getString("weather",null)!=null){
Intent intent=new Intent(this,WeatherActivity.class);
startActivity(intent);
finish();
}
}
}
<第二行代码>中的天气应用(5)--天气界面和天气活动(难)
title.xml
<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"android:layout_height="?attr/actionBarSize">
<Button
android:layout_width="30dp"
android:layout_height="30dp"
android:id="@+id/nav_button"
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_home"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/title_city"
android:layout_centerInParent="true"
android:textColor="#fff"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/title_update_time"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textColor="#fff"
android:textSize="16sp"/>
</RelativeLayout>
-------------------------------------------------------------------------------------------------------------
now.xml
<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns: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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/degree_text"
android:layout_gravity="end"
android:textColor="#fff"
android:textSize="60sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/weather_info_text"
android:layout_gravity="end"
android:textColor="#fff"
android:textSize="20sp"/>
</LinearLayout>
-------------------------------------------------------------------------------------------------------------
forecast.xml
<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns: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:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/forecast_layout"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
------------------------------------------------------------------------------------------------------------
aqi.xml
<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns: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: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:orientation="vertical"
android:layout_centerInParent="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/aqi_text"
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指数"
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:orientation="vertical"
android:layout_centerInParent="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/pm25_text"
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指数"
android:textColor="#fff"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
-----------------------------------------------------------------------------------------------------------
suggestion.xml
<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns: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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/comfort_text"
android:layout_margin="15dp"
android:textColor="#fff"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/car_wash_text"
android:layout_margin="15dp"
android:textColor="#fff"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/sport_text"
android:layout_margin="15dp"
android:textColor="#fff"/>
</LinearLayout>
------------------------------------------------------------------------------------------------------------
activity_weather.xml
<?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">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/bing_pic_img"
android:scaleType="centerCrop"/>
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/weather_layout"
android:scrollbars="none"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
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>
</android.support.v4.widget.SwipeRefreshLayout>
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/choose_area_fragment"
android:name="com.scx040407.myweather.ChooseAreaFragment"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
</FrameLayout>
-----------------------------------------------------------------------------------------------------------
以上是天气活动的布局文件:
title.xml用来显示标题的.
now.xml用来显示当前温度的.
forecast.xml用来显示预报的.
aqi.xml用来显示空气指数的.
suggestion.xml用来显示天气建议的.
最后用一个activity_weather.xml将上面的布局都引用进来,合成一个完整的天气界面布局.
DrawerLayout 是滑动菜单布局,里面应该有两个子布局,第一个是主界面布局ScrollView,第二个是滑动菜单的布局(碎片的好处体现在此)
SwipeRefreshLayout是下拉刷新布局,把ScrollView包住就行,用法比较简单.
-------------------------------------------------------------------------------------------------------------
天气活动 WeatherActivity
package com.scx040407.myweather;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.scx040407.myweather.gson.Forecast;
import com.scx040407.myweather.gson.Weather;
import com.scx040407.myweather.service.AutoUpdateService;
import com.scx040407.myweather.util.HttpUtil;
import com.scx040407.myweather.util.Utility;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
public class WeatherActivityextends AppCompatActivity {
public DrawerLayoutdrawerLayout;
private ButtonnavButton;
public SwipeRefreshLayoutswipeRefresh;
private StringmWeatherId;
private ImageViewbingPicImg;
private ScrollViewweatherLayout;
private TextViewtitleCity;
private TextViewtitleUpdateTime;
private TextViewdegreeText;
private TextViewweatherInfoText;
private LinearLayoutforecastLayout;
private TextViewaqiText;
private TextViewpm25Text;
private TextViewcomfortText;
private TextViewcarWashText;
private TextViewsportText;
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
/*
* 让背景图片和状态栏融合
* */
if (Build.VERSION.SDK_INT>=21){//如果是安卓5.0以上
//让背景图和状态栏融合,首先要拿到decorView
View decorView=getWindow().getDecorView();
//设置系统的UI显示,参数的意思是活动的布局会显示在状态栏上面
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
//状态栏设置成透明色
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
setContentView(R.layout.activity_weather);
drawerLayout= (DrawerLayout)findViewById(R.id.drawer_layout);
navButton= (Button)findViewById(R.id.nav_button);
navButton.setOnClickListener(newView.OnClickListener(){
@Override
public void onClick(View v){
drawerLayout.openDrawer(GravityCompat.START);//打开滑动菜
}
});
bingPicImg= (ImageView)findViewById(R.id.bing_pic_img);
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);
/*
*下拉刷新部分开始
**/
swipeRefresh= (SwipeRefreshLayout)findViewById(R.id.swipe_refresh);
//设置下拉刷新进度条颜色
swipeRefresh.setColorSchemeResources(R.color.colorPrimary);
//获取缓存实例
SharedPreferences prefs= PreferenceManager.getDefaultSharedPreferences(this);
//获取缓存中键是"weather"的内容返回字符串,没有就默认返回null
String weatherString=prefs.getString("weather",null);
if (weatherString!=null){
//缓存中weather字段的内容是上次退出时的区县weatherid
//拿着区县的weatherid去请求天气数据
Weather weather= Utility.handleWeatherResponse(weatherString);
mWeatherId=weather.basic.weatherId;
showWeatherInfo(weather);//调用显示天气的方法,将信息显示在天气界面上
}else{ //如果没有缓存信息,直接从Intent中获取
mWeatherId=getIntent().getStringExtra("weather_id");
weatherLayout.setVisibility(View.INVISIBLE);
requestWeather(mWeatherId);//调用请求天气的方法
}
//设置下拉刷新监听
swipeRefresh.setOnRefreshListener(newSwipeRefreshLayout.OnRefreshListener(){
@Override
public void onRefresh() {
requestWeather(mWeatherId);
}
});
/*
*下拉刷新部分结束
**/
/*
* 加载图片的部分开始
* */
String bingPic=prefs.getString("bing_pic",null);//从缓存中取出键对应的值,没有则默认为null
if (bingPic!=null){
Glide.with(this).load(bingPic).into(bingPicImg);//加载图片到imageview
}else{
loadBingPic();
}
}
//发送请求,获取图片
private void loadBingPic() {
String requestBingPic="http://guolin.tech/api/bing_pic";
HttpUtil.sendOkHttpRequest(requestBingPic,newCallback() {
@Override
public void onFailure(Callcall, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Callcall, Response response)throws IOException {
//响应格式类似这样
//http://cn.bing.com/az/hprichbg/rb/DeltaJunction_ZH-CN9901755694_1920x1080.jpg
final StringbingPic=response.body().string();
SharedPreferences.Editoreditor=PreferenceManager.getDefaultSharedPreferences
(WeatherActivity.this).edit();//获取editor
editor.putString("bing_pic",bingPic);//将图片链接放进去
editor.apply();//执行
runOnUiThread(newRunnable() {
@Override
public void run() {//切换回主线程直接加载链接到ImageView
Glide.with(WeatherActivity.this).load(bingPic).into(bingPicImg);
}
});
}
});
}
/*
* 加载图片的部分结束
* */
//发送请求,获取天气信息
public void requestWeather(finalStringweatherId) {
//拼接url
String weatherUrl="http://guolin.tech/api/weather?cityid="
+weatherId+"&key=8dc7d87967384263830fc9cce854451c";
HttpUtil.sendOkHttpRequest(weatherUrl,newCallback() {
@Override
public void onFailure(Callcall, 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(Callcall, Response response)throws IOException {
final StringresponseText=response.body().string();
final Weatherweather=Utility.handleWeatherResponse(responseText);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (weather!=null&"ok".equals(weather.status)){
//获取editor
SharedPreferences.Editor editor=PreferenceManager.
getDefaultSharedPreferences(WeatherActivity.this).edit();
editor.putString("weather",responseText);//将天气信息放进去
editor.apply();//执行
showWeatherInfo(weather);
}else{
Toast.makeText(WeatherActivity.this,"获取天气信息失败",
Toast.LENGTH_SHORT).show();
}
swipeRefresh.setRefreshing(false);//刷新事件结束后隐藏进度条
}
});
}
});
loadBingPic();//将请求图片放在这里意思是将天气信息和图片一起刷新.
}
//将天气信息显示到界面上
private void showWeatherInfo(Weatherweather) {
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="舒适度:"+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,AutoUpdateService.class);
startService(intent);
}
}
<第二行代码>中的天气应用(6)--service自动更新
package com.scx040407.myweather.service;import android.app.AlarmManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.content.SharedPreferences;import android.os.IBinder;import android.os.SystemClock;import android.preference.PreferenceManager;import com.scx040407.myweather.gson.Weather;import com.scx040407.myweather.util.HttpUtil;import com.scx040407.myweather.util.Utility;import java.io.IOException;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;/** 更新的意思是在后台即服务中发送请求,然后把响应数据存储到缓存中去* */public class AutoUpdateService extends Service { @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { updateWeather(); //更新天气 updateBingPic(); //更新背景图片 AlarmManager manager= (AlarmManager) getSystemService(ALARM_SERVICE); int anHour=8*60*60*1000 ; //8个小时的毫秒数 long triggerAtTime= SystemClock.elapsedRealtime()+anHour;//开机到现在的时间+8小时 Intent i=new Intent(this,AutoUpdateService.class); PendingIntent pi=PendingIntent.getService(this,0,i,0); manager.cancel(pi);//先取消掉,相当于初始化 //设置从开机时间算起,8个小时,启动服务. manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi); //这个返回的作用相当于初始化,把所有参数都清空了 //所以每过8小时都会自动更新 return super.onStartCommand(intent, flags, startId); } /* * 更新天气信息存入缓存文件 */ private void updateWeather() { SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(this); String weatherString=prefs.getString("weather",null); if (weatherString!=null){ Weather weather=Utility.handleWeatherResponse(weatherString); String weatherId=weather.basic.weatherId; String weatherUrl="http://guolin.tech/api/weather?cityid=" +weatherId+"&key=8dc7d87967384263830fc9cce854451c"; HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { String responseText=response.body().string(); Weather weather= Utility.handleWeatherResponse(responseText); if (weather!=null & "ok".equals(weather.status)){ SharedPreferences.Editor editor=PreferenceManager. getDefaultSharedPreferences(AutoUpdateService.this).edit(); editor.putString("weather",responseText); editor.apply(); } } }); } } /* * 更新背景图片存入缓存文件 */ private void updateBingPic() { 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 { String bingPic=response.body().string(); SharedPreferences.Editor editor=PreferenceManager. getDefaultSharedPreferences(AutoUpdateService.this).edit(); editor.putString("bing_pic",bingPic); editor.apply(); } }); }}
<第二行代码>中的天气应用(7)--总结
这个应用作为书中最后出现的大BOSS,对于初学者来说还是很有难度的.要考虑到的逻辑很多,控件很多.在敲代码的过程中遇到了几个小问题,也都解决掉了.
例如: response.body().string() 敲成了 response.body().toString() 结果就导致界面加载不出来而且进度条就一直在转,因为响应里面的东西无法解析,但是又不是响应失败,就一直转什么事情都不发生.
我从进度条开始入手,以为是进度条写的有问题.检查没问题后又去找请求,是不是请求错了地方?发现也没问题然后去找响应,发现了问题.改完代码好使了.
我觉得每写一段代码就要停下检查一次,这样能避免在代码复杂了以后出现错误无从下手.真的遇到了问题首先要调整好心态,顺藤摸瓜,心态好了才能更容易找到并解决问题.
这就是我学安卓近7周以来的心得体会.
- <第二行代码>中的天气应用
- <第二行代码>中的新闻应用
- 天气开发1——第二行代码(酷欧天气)
- 天气开发2——第二行代码(酷欧天气)
- 天气开发3——第二行代码(酷欧天气)
- 天气开发4——第二行代码(酷欧天气)
- [应用代码] Android之简洁天气应用
- iOS 天气应用代码中文介绍
- Google天气API在RCP中的应用
- 天气代码
- 天气代码
- SunDay天气--第二弹
- 骑行应用开发《三》天气
- kotlin版的酷欧天气 (郭林大神的第一行代码第二版)
- 基于《第一行代码第二版》的天气app的扩展开发
- volatile代码中的应用
- windows 8 天气应用
- Android天气应用“SimpleWeather”
- Android自定义View画出一个时钟(时针、分针、秒针)完美搭配当前时间走动
- SimpleDateFormat使用,有时区的格式
- 从配置角度来说制约linux高并发的两个点
- jquery操作select(取值,设置选中)
- PrintWriter打印流实例
- <第二行代码>中的天气应用
- [PHP]
- okhttp多图上传
- CentOS 下配置vsftpd,匿名可上传可下载
- 小白题解 Codeforces 804A Find Amir
- mysql中TIMESTAMP设置默认值的灵活运用
- python参数的传入 * ,**
- computed和methods里面使用switch分别处理
- Linux下实现myshell的重定向