郭神提供的数据接口,包含全国省市县名称和编号信息:
省级单位:
http://guolin.tech/api/china
服务器会返回JSON格式数据
市级单位:在后面加上具体省份id即可
http://guolin.tech/api/china/16
县级单位以此类推:
http://guolin.tech/api/china/16/116
接着为了获取每个地区具体的天气情况需要注册和风天气的接口:
拿到自己App的API KEY
之后配合每个具体地区的weather_id即可查看天气信息,如:
http://guolin.tech/api/weathercityid=cn101190401&key=bc0418b57b2d4918819d3974ac1285d9
返回的数据如:
数据获取后接着做JSON解析工作即可。
第一阶段要做的就是创建好数据库和表,从而将服务器获取到的数据存储到本地。这里使用 LitePal来管理数据库。
首先创建目录结构 ,其中db包用于存放数据库模型相关的代码
gson包用于存放GSON模型相关的代码,
service包用于存放服务相关的代码
util包用于存放工具相关的代码。
添加相关依赖:
使用 LiteRal,可以用面向对象的思维来实现数据库相关操作,比如定义一个 Java bean,在Book类中我们定义了id、 author、 price、 pages、name这几个字段,并生成了相应的 getter和 setter方法。Book类就会对应数据库中的Book表,而类中的每一个字段分别对应了表中的每一个列,这就是对象关系映射最直观的体验。
在db下新建省市县三个bean来对应三张表,具体代码如下:
/**
*省信息表
*/
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;
}
}
LiteRal进行表管理操作时不需要模型类有任何的继承结构,但是进行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;
}
}
/**
* 地区/县信息表
*/
public class County extends DataSupport {
private int id;
private String countyName;//县名
private String weatherId;//天气id
private int cityId;//所属县ID
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 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;
}
}
接下来需要配置``litepal.xml`
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value ="MyWeatherApp"/>
<version value="1"/>
<list>
<mapping class="com.wz.myweatherapp.db.County"/>
<mapping class="com.wz.myweatherapp.db.City"/>
<mapping class="com.wz.myweatherapp.db.Province"/>
</list>
</litepal>
其中,< dbname>标签用于指定数据库名,< version>标签用于指定数据库版本号,
标签用于指定所有的映射模型,我们稍后就会用到。
最后还需要再配置一下 LitePalApplication,修改 Androidmanifest xml中的代码,如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wz.myweatherapp">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name="org.litepal.LitePalApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
......
由于数据是从网络服务端获取的,故可以创建工具类
public class HttpUtil {
/**
* 传入请求地址 注册一个回调来处理服务器响应
* @param address
* @param callback
*/
public static void sendOkHttpRequest(String address,Callback callback){
//创建一个OkHttpClient实例
OkHttpClient client = new OkHttpClient();
//创建Request来发起HTTP请求
Request request = new Request.Builder().url(address).build();
//之后调用OkhttpClient的newCall()方法来创建一个CalL对象,并调用它的execute()方
//法来发送请求并获取服务器返回的数据,写法如下
client.newCall(request).enqueue(callback);
}
}
另外,由于服务器返回的省市县数据都是JSON格式的,所以最好再提供一个工具类来解析和处理这种数据。在util包下新建一个 Utility类,代码如下所示
public class Utility {
/**
* 解析处理服务器返回的省级数据
*
*/
public static boolean handleProvinceResponse(String response){
if (!TextUtils.isEmpty(response)) {
try {
//可以看到,解析JSON的代码非常简单,由于在服务器中定义的是一个JSON数组,
//因此这里首先是将服务器返回的数据传入到了一个JSONArray对象中。然后循环遍历这个JSONArray,
// 从中取出的每一个元素都是一个JSONArray对象,每个JSONArray对象中又会包含id、name和 version这些数据。
//接下来只需要调用 getstring()方法将这些数据取出,并打印出来即可。
//先使用JSONArray 和 JSONObject将数据解析
JSONArray allProvince = new JSONArray(response);
for (int i = 0; i < allProvince.length(); i++) {
JSONObject provinceObject = allProvince.getJSONObject(i);
//装入实体对象
Province province = new Province();
province.setProvinceName(provinceObject.getString("name"));
province.setProvinceCode(provinceObject.getInt("id"));
//由于province 继承了litepal特性 故使用save存储进数据库
province.save();
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 解析处理服务器返回的市级数据
*/
public static boolean handleCityResponse(String response,int provinceId){
try {
if (!TextUtils.isEmpty(response)) {
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){
try {
if (!TextUtils.isEmpty(response)) {
JSONArray allCounties = new JSONArray(response);
for (int i = 0; i < allCounties.length(); i++) {
JSONObject countyObject = allCounties.getJSONObject(i);
County county = new County();
county.setCityId(cityId);
county.setCountyName(countyObject.getString("name"));
county.setWeatherId(countyObject.getString("weather_id"));
county.save();
}
return true;
}
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
}
需要准备的工具类就这么多,现在可以开始写界面了。由于遍历全国省市县的功能我们在后面还会复用,因此就不写在活动里面了,而是写在碎片里面,这样需要复用的时候直接在布局里面引用碎片就可以了。
<?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:layout_centerInParent="true"
android:textSize="20sp"
android:textColor="#fff"
/>
<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>
接下来也是最关键的一步,需要编写用于加载省市县数据的碎片了。新建 ChooseAreaFragment继承自 Fragment这个逻辑却不复杂,需要慢慢理一下。在 onCreateview()方法中先是获取到了一些控件的实例,然后去初始化了 Array Adapter,并将它设置为 List view的适配器。接着在 onActivityCreated()方法中给 Listview和Button设置了点击事件,到这里初始化工作就算是完成了。
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.choose_area, container, false);
mTitleText = view.findViewById(R.id.title_text);
mButton = view.findViewById(R.id.back_button);
mListView = view.findViewById(R.id.list_view);
//不过,数组中的数据是无法直接传递给 Listview的,我们还需要借助适配器来完成。 Android
//中提供了很多适配器的实现类,其中我认为最好用的就是 Array Adapter。它可以通过泛型来指定
//要适配的数据类型,然后在构造函数中把要适配的数据传入。 Array Adapter有多个构造函数的重
//载,你应该根据实际情况选择最合适的一种。这里如果提供的数据都是字符串,可以将
//ArrayAdapter的泛型指定为 String
// 然后在ArrayAdapter的构造函数中依次传入当前上下文,List view子项布局的id,以及要适配的数据。
// 注意,使用了simple_list_item_1作为 List view子项布局的id,这是一个 Android内置的布局文件,里面只有一个
//Text View,可用于简单地显示一段文本。这样适配器对象就构建好了
//最后,还需要调用 List View的 setAdapter()方法,将构建好的适配器对象传递进去,这样
//List view和数据之间的关联就建立完成了。
adapter = new ArrayAdapter<>(getContext(),android.R.layout.simple_list_item_1,dataList);
mListView.setAdapter(adapter);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
/*
列表点击事件
*/
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
//可以看到,我们使用 setonItemClicklistener()方法为 Listview注册了一个监听器,当
//用户点击了 Listview中的任何一个子项时,就会回调 onItemclick()方法。在这个方法中可以
//通过 position参数判断出用户点击的是哪一个子项,然后获取到相应的类信息,并通过Toast显示
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long idl) {
if (currentLevel == LEVEL_PROVINCE){
selectedProvince = provinceList.get(pos);
queryCity();
}else if (currentLevel == LEVEL_CITY){
selectedCity = cityList.get(pos);
queryCounty();
}
}
});
/*
返回按钮 点击事件
*/
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (currentLevel == LEVEL_COUNTY){
/*
如果是在县页面返回 则获取市信息
*/
queryCity();
}else if (currentLevel == LEVEL_CITY){
/*
如果实在市级别返回 则获取省信息
*/
queryProvince();
}
}
});
/*
创建时默认获取省信息
*/
queryProvince();
}
/*
查询省内所有市
*/
private void queryCity() {
mTitleText.setText(selectedProvince.getProvinceName());
mButton.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();
mListView.setSelection(0);
currentLevel = LEVEL_CITY;
}else {
int provinceCode = selectedProvince.getProvinceCode();
String address ="http://guolin.tech/api/china/"+provinceCode;
queryFromServer(address,"city");
}
}
/*
查询全国所有省 优先从数据可查询 若无再去服务器查询
query Provinces()方法中首先会将头布局的标题设置成中国,将返回按钮
隐藏起来,因为省级列表已经不能再返回了。然后调用 LiteRal的查询接口来从数据库中读取省
级数据,如果读取到了就直接将数据显示到界面上,如果没有读取到组装出一个请求地址,
然后调用 queryFromServer()方法来从服务器上查询数据。
*/
private void queryProvince() {
mTitleText.setText("中国");
//另外还有一点需要注意,在返回按钮的点击事件里,会对当前 List view的列表级别进行判断。
//如果当前是县级列表,那么就返回到市级列表,如果当前是市级列表,那么就返回到省级表列表。
//当返回到省级列表时,返回按钮会自动隐藏,从而也就不需要再做进一步的处理了。
mButton.setVisibility(View.GONE);
provinceList = DataSupport.findAll(Province.class);
if (provinceList.size() > 0) {
dataList.clear();
for (Province province : provinceList) {
dataList.add(province.getProvinceName());
}
adapter.notifyDataSetChanged();
mListView.setSelection(0);
currentLevel = LEVEL_PROVINCE;
}else {
String address = "http://guolin.tech/api/china";
queryFromServer(address, "province");
}
}
/**
* query Fromserver()方法中会调用 HttpUtil的send0httPrequest()方法来向服务器发送
* 请求,响应的数据会回调到 onResponse()方法中,然后我们在这里去调用 Utility的
* handleprovincesresponse()方法来解析和处理服务器返回的数据,并存储到数据库中。接下
* 来的一步很关键,在解析和处理完数据之后,再次调用了 queryProvinces()方法来重新加
* 载省级数据,由于 queryProvinces()方法牵扯到了U操作,因此必须要在主线程中调用,这
* 里借助了 runonuiThread()方法来实现从子线程切换到主线程。现在数据库中已经存在了数据
* 因此调用 queryProvinces()就会直接将数据显示到界面上了
* @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 responseText = response.body().string();
boolean result = false;
if ("province".equals(type)) {
result = Utility.handleProvinceResponse(responseText);
}else if ("city".equals(type)){
result = Utility.handleCityResponse(responseText,selectedProvince.getId());
}else if ("county".equals(type)){
result = Utility.handleCountyResponse(responseText,selectedCity.getId());
}
if (result){
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
if ("province".equals(type)){
queryProvince();
}else if ("city".equals(type)){
queryCity();
}else if ("county".equals(type)){
queryCounty();
}
}
});
}
}
});
}
private void closeProgressDialog() {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
}
private void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.setMessage("正在加载");
mProgressDialog.setCanceledOnTouchOutside(false);
}
mProgressDialog.show();
}
/*
查询市内所有区/县
*/
private void queryCounty() {
mTitleText.setText(selectedCity.getCityName());
mButton.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();
mListView.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");
}
}
这样我们就把加载全国省市县的功能完成了,可是碎片是不能直接显示在界面上的,因此我们还需要把它添加到活动里才行。修改 activity main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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.wz.myweatherapp.ChooseAreaFragment"
/>
</FrameLayout>
另外,我们刚才在碎片的布局里面已经自定义了一个标题栏,因此就不再需要原生的Action bar了,修改res/ values/ styles.xml中的代码,如下所示
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
声明所需网络权限
<uses-permission android:name="android.permission.INTERNET"/>
现在可以运行一下程序进行测试了,效果如下。
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法