




已阅读5页,还剩25页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
重庆邮电大学研究生堂下考试答卷 2017-2018 学年 第 1 学期考试科目 物联网导论 任课老师 王平 姓 名 饶华阳 学 号 S170301016 年 级 2017级 学 院 自动化学院 专 业 控制科学与工程 2017年 12 月 27 日目录基于Android平台的天气查询APP3一、功能需求及技术可行性分析3二、APP运行要求42.1 运行平台42.2 版本4三、创建数据库和表43.1 加载依赖库43.2 建立表和数据库5四、遍历全国省市县数据64.1 HttpUtil类:网络请求类64.2 Utility类:解析处理JSON数据64.3 choose_area.xml布局74.4 ChooseAreaFragment类:碎片布局逻辑函数7五、显示天气信息85.1 定义GSON实体类85.2 编写天气界面95.3 天气App显示结果9六、附录116.1 ChooseAreaFragment源代码116.2 WeatherActivity源代码23基于Android平台的天气查询APP每个智能手机都会自带一个天气APP,天气信息能实时更新显示在手机界面上。目前天气APP的设计偏向精准,省流量,人性化UI等方面,因此编写一个功能较为完整的天气预报程序是值得实践的,通过该天气APP编写能极大的提高我们的Android开发综合能力。一、功能需求及技术可行性分析经过对程序的功能需求分析,将功能需求整理后,该天气APP的中有以下功能:(1) 可以罗列出全国所有的省、市、县;(2) 可以查询任意城市的天气信息;(3) 能够自由切换城市,并查看其天气信息;(4) 有下拉刷新天气信息以及后台自动更新功能。关于技术可行性分析,能从服务器上获取实时天气信息是首先值得考虑的。经过查阅资料,开放性天气接口网址如下:(1) 罗列全国所有省份接口:http:/guolin.tech/api/china(2) 所查询的某省的城市接口:http:/guolin.tech/api/china+该省代号(3) 查询某省某市某县接口:http:/guolin.tech/api/china+该省代号+该市代号(4) 查询待查城市天气信息:http:/guolin.tech/api/china+该省代号+该市代号+天气id+ API Key二、APP运行要求2.1 运行平台开发平台:Android studio 2.3.3版本模拟器:Genymotion虚拟设备:Google Nexus5X-7.0.0-API24-10801920 2.2 版本compileSdkVersion 26buildToolsVersion 27.0.1minSdkVersion 23targetSdkVersion 26若要用Android studio运行此软件,第一次加载程序包是请更改一下build.gradle中与你电脑上版本相符合的相关配置。三、创建数据库和表3.1 加载依赖库将项目所需要的各种依赖库进行声明,编辑app/build.gradle文件,在dependencies闭包中添加如下内容:3.2 建立表和数据库建立3个表:province、city、county。每个表分别存放省、市、县的数据。其对应的实体类,建立Province、City、County这三个类。配置litepal,xml文件,app/src/main-New-Directory创建assets包,再建litepal.xml文件,内容如下图。将数据库名称指定为app_weather,数据库版本为1,并将Province、City、County这三个类添加到映射列表中。最后还需要配置一下LitePalApplication,在AndroidManifest.xml中的application添加:android:name=org.litepal.LitePalApplication四、遍历全国省市县数据4.1 HttpUtil类:网络请求类从服务器获取全国省市县的数据:在util包下增加一个HttpUtil类,实现网络申请4.2 Utility类:解析处理JSON数据对服务器返回的省市县JSON格式数据进行解析和处理:util包下建立Utility类,提供了handleProvinceResponse、handleCityResponse、handleCountyResponse三个方法,分别用于解析和处理服务器返回的省级、市级、县级数据。以下列举一个解析和出路服务器返回的市级数据。4.3 choose_area.xml布局编写遍历全国省市县的数据显示界面,卸载碎片里,复用直接在布局里引用碎片。详细代码见附录,如下是改布局效果图。图1 choose_area.xml布局碎片不能直接显示在界面上,我们需要把它在activity_main.xml中添加上。4.4 ChooseAreaFragment类:碎片布局逻辑函数这个类的代码分别为以下三类功能函数:(1) 在onCreateView()方法中,获取控件实例,并初始化ArrayAdapter,将它设置为ListView的适配器;onActivityCreated()方法中给ListView和Button设置点击事件。(2) queryProvinces()、queryCities()、queryCounties()三个方法用于访问省市县数据,调用LitePal的查询接口优先从数据库中读取,若数据库没有,调用queryFromServer()方法从服务器上查询数据。(3) queryFromServer()调用HttpUtil类(网络请求类)根据queryCities()等法法提交的相应县级代号查询服务器,并调用Utility类来析处理JSON数据,并显示到界面上由于此部分代码非常多,请见附录源码,里面有详细说明。五、显示天气信息5.1 定义GSON实体类在GOSN包中将返回的天气数据对应的实体类创建好:Bisic、Aqi、Now、Suggestion、Forecast、Weather。在Weather类中对Bisic、Aqi、Now、Suggestion、Forecast类进行引用,而daily_forecast中包含一个数据,因此用List集合啦进行Forecast类引用。5.2 编写天气界面创建显示天气信息的活动:WeatherActivity,并将其布局名称指定为activity_weather.xml。在建立头布局,以及Bisic、Aqi、Now、Suggestion、Forecast类所对应的布局,将他们引入集成到activity_weather.xml。其界面效果效果如下图所示。图2 天气界面布局图5.3 天气App显示结果(1)首先将在utility类中添加一个解析天气的JSON数据方法。(2)在活动中去请求天气数据,并将数据展示到界面上。以下是请求天气数据的关键代码,以及初步显示结果。(4) 采用下拉刷新方式对天气信息进行手动更新。(5) 实现切换城市功能,通过把碎片放入到滑动菜单中使用来实现此功能。(6) 实现后台自动更新功能。(7) 修改APP图标和名称以上所有功能函数代码详情请见附件,内有详细说明。下面是整体的效果图:六、附录详情天气APP的源程序请见源程序压缩包。以下是部分主要代码。6.1 ChooseAreaFragment源代码/* * Created by RHY on 2017/12/26. * 遍历省市县数据碎片 */public class ChooseAreaFragment extends Fragment public static final int LEVEL_PROVINCE = 0; public static final int LEVEL_CITY = 1; public static final int LEVEL_COUNTY = 2; private ProgressDialog progressDialog; private TextView titleText; private Button backButton; private ListView listView; private ArrayAdapter adapter; private List dataList = new ArrayList(); /省列表 private List provinceList; /市列表 private List cityList; /县列表 private List countyList; /选中的省份 private Province selectedProvince; /选中的城市 private City selectedCity; /当前选中的级别 private int currentLevel; /获取一些空间的实例,再初始化 ArrayAdapter 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.MyListView); adapter = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, dataList); listView.setAdapter(adapter); /初始化ArrayAdapter,(在下)将它设置为ListView 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(); /调用碎片中的getActivity()方法,再利用instanceof关键字,能轻松判断该碎片在MainActivity中还是WeatherActivity中。 /在MainActivity中,处理逻辑不变 if (getActivity() instanceof MainActivity) Intent intent = new Intent(getActivity(), WeatherActivity.class); intent.putExtra(weather_id, weatherId); startActivity(intent); getActivity().finish(); /如果过是WeatherActivity中,就关闭掉滑动菜单,显示下拉刷新进度条,然后u请求天气税局 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(); /* * 查询全国所有的省queryProvinces();优先从数据库查询,没有上服务器去查询 */ private void queryProvinces() titleText.setText(中国);/首先将头布局的标题设置为中国 backButton.setVisibility(View.GONE);/将返回按钮隐藏起来,因为省级列表不能再返回 provinceList = DataSupport.findAll(Province.class);/调用LitePal的查询接口从数据库读取省级数据 if (provinceList.size() 0) dataList.clear(); for (Province province : provinceList) dataList.add(province.getProvinceName(); adapter.notifyDataSetChanged(); listView.setSelection(0); currentLevel = LEVEL_PROVINCE; /没有读取到数据就组装一个请求地址,使用queryFromServer()方法从服务器上查询数据 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 传入的数据类型String */ private void queryFromServer(String address, final String type) showProgressDialog();/显示进度条框,下面用sendOkHttpRequest()方法向服务器发送请求 / 返回数据会回调到onResponse()来解析和处理,并存储 HttpUtil.sendOkHttpRequest(address, new Callback() Override /请求成功的回调 public void onResponse(Call call, Response response) throws IOException /异常处理并多次读取 String responseText = response.body().string(); boolean result = false; if (province.equals(type) result = Utility.handleProvinceResponse(responseText); /handleProvinceResponse(responseText)用来解析和处理服务器返回的数据,并存储 else if (city.equals(type) result = Utility.handleCityResponse(responseText, selectedProvince.getId(); else if (county.equals(type) result = Utility.handleCountyResponse(responseText, selectedCity.getId(); /数据已经解析处理完毕,result为真,接下来关闭进度条,并存储进数据库, / 设计UI操作,因此必须在主线程中调用,借助runOnUiThread()方法实现从子线程切换到主线程 /当数据库已经存在数据了,所以每次queryProvinces()就会有数据显示到界面 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) /通过runOnUiThread()方法回到主线程处处理逻辑 getActivity().runOnUiThread(new Runnable() Override public void run() closeProgressDialog(); Toast.makeText(getContext(), 加载失败, Toast.LENGTH_SHORT).show(); ); ); /* * 显示进度对话框 */ private void showProgressDialog() if (progressDialog = null) /noinspection deprecation progressDialog = new ProgressDialog(getActivity(); progressDialog.setMessage(正在加载.); progressDialog.setCanceledOnTouchOutside(false); progressDialog.show(); /* * 关闭进度对话框 */ private void closeProgressDialog() if (progressDialog != null) progressDialog.dismiss(); 6.2 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; /下拉刷新功能需要 public SwipeRefreshLayout swipeRefresh; private String mWeatherId; /切换城市功能用 public DrawerLayout drawerLayout; private Button navButton; 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.fort_text); carWashText = (TextView) findViewById(R.id.car_Wash_text); sportText = (TextView) findViewById(R.id.sport_text); /初始化切换城市功能更控件 drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); navButton = (Button) findViewById(R.id.nav_button); /打开切换天气的滑动菜单 navButton.setOnClickListener(new View.OnClickListener() Override public void onClick(View v) drawerLayout.openDrawer(GravityCompat.START); ); /初始化下拉刷新控件 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); /设置一个下拉刷新监听器,触发了下拉操作,就会用监听器的onRefresh()方法 /onRefresh()方法调用requestWeather()方法请求天气信息 swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() Override public void onRefresh() requestWeather(mWeatherId); ); /根据天气ID请求城市天气信息 public void requestWeather(final String weatherId) String weatherUrl = http:/guolin.tech/api/weather?cityid= + weatherId + &key=b2092796a161422c83b312cc224d7010; HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() Override public void onResponse(Call call, Response response) throws IOException final String responseText = response.body().string(); final Weather weather = Utility.handleWeatherResponse(responseText); runOnUiThread(new Runnable() Override public void run() if (weather != null & ok.equals(weather.status) SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(WeatherActivity.this).edit(); editor.putString(weather, responseText); editor.apply(); mWeatherId = weather.basic.weatherId; showWeatherInfo(weather); else Toast.makeText(WeatherActivity.this, 获取天气信息失败, Toast.LENGTH_SHORT).show(); swipeRefresh.setRefreshing(false); ); 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实体类中的数据 * * param weather */ private void showWeatherInfo(Weather weather) String cityName = weather.basic.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 商洛市中石化2025秋招笔试提升练习题含答案
- 贺州市中石化2025秋招面试半结构化模拟题及答案法律与合规岗
- 2025年科目循环考试题及答案
- 福建地区中石化2025秋招笔试综合知识专练题库及答案
- 焦作市中石油2025秋招面试半结构化模拟题及答案油气储运与管道岗
- 绍兴市中石油2025秋招面试半结构化模拟题及答案炼化装置操作岗
- 2025年社会文学考试题及答案
- 马鞍山市中石化2025秋招面试半结构化模拟题及答案机械与动力工程岗
- 中国联通酒泉市2025秋招综合管理类专业追问清单及参考回答
- 朔州市中石油2025秋招网申填写模板含开放题范文
- 太原市房屋租赁合同
- 体力活动金字塔
- 铜仁市大学生乡村医生专项计划招聘考试真题
- 土地综合整治投标方案(技术方案)
- JJF(皖) 174-2024 重点用能单位能源资源计量在线审查规范
- JGJ-T+141-2017通风管道技术规程
- 历年全国《宪法》知识竞赛试题库完整版及答案【历年真题】
- 基本乐理(师范教育专业)全套教学课件
- JJG 270-2008血压计和血压表
- 《解剖学基础》课件-上肢骨及其连接
- 轻质燃料油安全技术说明书样本
评论
0/150
提交评论