12.1 牛刀小试——巴士天气
经过前面的学习,相信大家对Android有了更加深入地了解,所谓学以致用,接下来我们将进入实战的课程。
开发一个完整的应用(Application,后面简称App),我们要知道以下几个问题:做的是什么?需要什么?如何去做?本章将围绕这三个问题以“巴士天气”为例,简单实现一个天气类Android应用。
12.1 功能需求及技术可行性分析
在开始编码之前,我们需要先对App进行需求分析,想一想一款天气预报工具应该具备哪些功能。将这些功能全部整理出来之后,我们才好动手去一一实现。这里我整理了一下,巴士天气中至少应该具备以下功能:
可以罗列出全国所有的省、市县
可以查看全国任意城市的天气信息
可以自由切换城市,去查看其他城市的天气
后台自动更新
可以应用到多媒体功能
虽然看上去只有5个主要的功能点,但如果想要全部实现这些功能却需要用到UI、网络、数据存储、服务,多媒体等技术,因此还是非常考验你的综合应用能力的。不过好在这些技术在前面的章节中我们全部都学习过了,只要你学得用心,相信完成这些功能对你来说并不难。
分析完了需求之后,接下来就要进行技术可行性分析了。首先要考虑的问题就是全国的各省市,以及对应的天气数据源。正好安卓巴士有合作方提供了相关的Api可以满足。Mob.com到官网可以看到有两个Api刚好满足我们的需求:
根据城市名查询天气(http://apicloud.mob.com/v1/weather/query)
请求方式:GET
请求参数:
| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| key | string | 是 | 用户申请的appkey(可以直接用网站的测试AppKey-520520test) |
| city | string | 是 | 城市名 |
| province | string | 是 | 当前城市的所属省市 如:北京-北京-通州、江苏-苏州-吴中(url编码) |
Json返回实例:
{ 'msg': 'success', 'result': [
{ 'airCondition': '良', 'city': '北京', 'coldIndex': '低发期', 'updateTime': '20150908153820', 'date': '2015-09-08', 'distrct': '门头沟', 'dressingIndex': '短袖类', 'exerciseIndex': '适宜', 'future': [
{ 'date': '2015-09-09', 'dayTime': '阵雨', 'night': '阴', 'temperature': '24°C/18°C', 'week': '星期三', 'wind': '无持续风向小于3级'
},
{ 'date': '2015-09-10', 'dayTime': '阵雨', 'night': '阵雨', 'temperature': '22°C/15°C', 'week': '星期四', 'wind': '无持续风向小于3级'
},
{ 'date': '2015-09-11', 'dayTime': '阴', 'night': '晴', 'temperature': '23°C/15°C', 'week': '星期五', 'wind': '北风3~4级无持续风向小于3级'
},
{ 'date': '2015-09-12', 'dayTime': '晴', 'night': '晴', 'temperature': '26°C/13°C', 'week': '星期六', 'wind': '北风3~4级无持续风向小于3级'
},
{ 'date': '2015-09-13', 'dayTime': '晴', 'night': '晴', 'temperature': '27°C/16°C', 'week': '星期日', 'wind': '无持续风向小于3级'
},
{ 'date': '2015-09-14', 'dayTime': '晴', 'night': '多云', 'temperature': '27°C/16°C', 'week': '星期一', 'wind': '无持续风向小于3级'
},
{ 'date': '2015-09-15', 'dayTime': '少云', 'night': '晴', 'temperature': '26°C/14°C', 'week': '星期二', 'wind': '南风3级南风2级'
},
{ 'date': '2015-09-16', 'dayTime': '局部多云', 'night': '少云', 'temperature': '26°C/15°C', 'week': '星期三', 'wind': '南风3级南风2级'
},
{ 'date': '2015-09-17', 'dayTime': '阴天', 'night': '局部多云', 'temperature': '26°C/15°C', 'week': '星期四', 'wind': '东南风2级'
}
], 'humidity': '湿度:46%', 'province': '北京', 'sunset': '18:37', 'sunrise': '05:49', 'temperature': '25℃', 'time': '14:35', 'washIndex': '不适宜', 'weather': '多云', 'week': '周二', 'wind': '南风2级'
}
], 'retCode': '200'}城市列表查询接口(http://apicloud.mob.com/v1/weather/citys)
请求方式:GET
请求参数:
| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| key | string | 是 | 用户申请的appkey(可以直接用网站的测试AppKey-520520test) |
返回Json示例:
{ 'msg': 'success', 'result': [
{ 'province':'安徽', 'city': [
{ 'city': '合肥', 'district': [
{ 'district': '合肥'
},
{ 'district': '长丰'
},
{ 'district': '肥东'
},
{ 'district': '肥西'
},
{ 'district': '巢湖'
},
{ 'district': '庐江'
}
]
},
{ 'city': '蚌埠', 'district': [
{ 'district': '蚌埠'
},
{ 'district': '怀远'
},
{ 'district': '固镇'
},
{ 'district': '五河'
}
]
},
{ 'city': '芜湖', 'district': [
{ 'district': '芜湖'
},
{ 'district': '繁昌'
},
{ 'district': '芜湖县'
},
{ 'district': '南陵'
},
{ 'district': '无为'
}
]
},
{ 'city': '淮南', 'district': [
{ 'district': '淮南'
},
{ 'district': '凤台'
},
{ 'district': '潘集'
}
]
},
{ 'city': '马鞍山', 'district': [
{ 'district': '马鞍山'
},
{ 'district': '当涂'
},
{ 'district': '含山'
},
{ 'district': '和县'
}
]
}
]
}
]
}数据源已经有了,下面整理了需要用到的知识点。
网络请求-HttpURLConnection
数据存储-SharedPreference,GreenDao
后台更新-Service
多媒体播放-MediaPlayer
UI-SurfaceView,三级联动布局
以上知识点如果大家还不熟悉的话,可以跳到前面的章节。
12.2 创建数据库和表
从本节开始,我们就要真正地动手编码了。
AndroidStudio项目搭建
1. 项目结构树
合理的项目结构也非常重要,这里需要在com.apkbus.weather包下面再建几个包。
activity:存放应用所有的Activity
api:存放网络请求相关的类
base:存放Application,以及BaseActivity等父类
db:存放数据库相关的表模型以及工具类
entry:存放数据模型
fragment:存放fragment
service:存放service
sharedPreference:存放sharedPreference的相关key模型
utils:存放工具类
weheel——widget:三级联动控件
2. Gradle配置
项目父级
build.gradle的设置如下:
buildscript {
ext.kotlin_version = '1.1.51'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
task clean(type: Delete) { delete rootProject.buildDir
}内部build.gradle的设置如下:
apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'apply plugin: 'org.greenrobot.greendao'android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
applicationId 'com.apkbus.weather'
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName '1.0'
}
buildTypes {
greendao {
schemaVersion 1// 这个地方是自动生成的配置文件存放在哪个位置的
targetGenDir 'src/main/java'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version'
implementation 'org.greenrobot:greendao:3.2.2'
compile 'net.zetetic:android-database-sqlcipher:3.5.1@aar'
compile 'com.google.code.gson:gson:2.8.1'
compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.31'}以上分别是配置GreenDao,Kotlin,Gjson以及recycleView的第三方adapter帮助库
数据库
1. 建表
回顾前面的Api文档,可以看到省市区的结构,为查询效率我们可以建三张表。在db的包下面再新建个包bean
省:
@Entity(indexes = arrayOf(Index(value = 'provinceName')))class ProvinceBean {
@Id(autoincrement = true) var id: Long = 0
var provinceName: String? = null
var level = LEVEL_PROVINCE
@Generated(hash = 1999810692) constructor(id: Long, provinceName: String, level: Int) { this.id = id this.provinceName = provinceName this.level = level
}
@Generated(hash = 1410713511) constructor()
}市
@Entity(indexes = arrayOf(Index(value = 'cityName'), Index(value = 'provinceName')))class CityBean {
@Id(autoincrement = true) var id: Long = 0
var cityName: String? = null
var provinceName: String? = null
var level = LEVEL_CITY
@Generated(hash = 83209856) constructor(id: Long, cityName: String, provinceName: String, level: Int) { this.id = id this.cityName = cityName this.provinceName = provinceName this.level = level
}
@Generated(hash = 273649691) constructor()
}区
@Entity(indexes = arrayOf(Index(value = 'cityName'), Index(value = 'districtName')))class DistrictBean {
@Id(autoincrement = true) var id: Long = 0
var cityName: String? = ''
var districtName: String? = ''
var level = LEVEL_DISTRICT
@Generated(hash = 903270775) constructor(id: Long, cityName: String, districtName: String, level: Int) { this.id = id this.cityName = cityName this.districtName = districtName this.level = level
}
@Generated(hash = 326445391) constructor()
}用level来区分省市区,方便后面根据level来查对应的数据表:
val LEVEL_PROVINCE = 0//省 直辖市 自治区val LEVEL_CITY = 1//市val LEVEL_DISTRICT = 2//区县
2. 初始化GreenDao以及编写数据库帮助类
GreenDao初始化,在db包下面新建MyOpenHelper类配置GreenDao的属性:
class MyOpenHelper : DaoMaster.DevOpenHelper {
constructor(context: Context, name: String) : super(context, name)
constructor(context: Context, name: String, factory: SQLiteDatabase.CursorFactory) : super(context, name, factory)
override fun onUpgrade(db: Database?, oldVersion: Int, newVersion: Int) {
/*此处不用super,因为父类中包含了
dropAllTables(db, true);
onCreate(db);
需要自己定制升级
*/
// MigrationHelper.getInstance().dropAndCreate(db);
}
}为使GreenDao为单例,需要在Application中声明,所以我们需要先自定义Applation。在base包下面新建MyApplication

然后在AndroidManifest.xml的<application>节点下加入或者修改
android:name='.base.MyApplication'
build一下程序,使得GreenDao插件生成模版代码。
因为三张表只会进行插入操作,所有我们需要把ProvinceBeanDao,CityBeanDao,DistrictBeanDao中的hasKey方法返回为false
@Override
public boolean hasKey(ProvinceBean entity) { return false;
}这样数据库表以及GreenDao框架就初始化完毕了。





































苏公安网备 32011402010933号