文档管理中心

第12章 实战之巴士天气(转载)

12.1 牛刀小试——巴士天气

经过前面的学习,相信大家对Android有了更加深入地了解,所谓学以致用,接下来我们将进入实战的课程。

开发一个完整的应用(Application,后面简称App),我们要知道以下几个问题:做的是什么?需要什么?如何去做?本章将围绕这三个问题以“巴士天气”为例,简单实现一个天气类Android应用。

12.1 功能需求及技术可行性分析

在开始编码之前,我们需要先对App进行需求分析,想一想一款天气预报工具应该具备哪些功能。将这些功能全部整理出来之后,我们才好动手去一一实现。这里我整理了一下,巴士天气中至少应该具备以下功能:

  • 可以罗列出全国所有的省、市县

  • 可以查看全国任意城市的天气信息

  • 可以自由切换城市,去查看其他城市的天气

  • 后台自动更新

  • 可以应用到多媒体功能

虽然看上去只有5个主要的功能点,但如果想要全部实现这些功能却需要用到UI、网络、数据存储、服务,多媒体等技术,因此还是非常考验你的综合应用能力的。不过好在这些技术在前面的章节中我们全部都学习过了,只要你学得用心,相信完成这些功能对你来说并不难。

分析完了需求之后,接下来就要进行技术可行性分析了。首先要考虑的问题就是全国的各省市,以及对应的天气数据源。正好安卓巴士有合作方提供了相关的Api可以满足。Mob.com到官网可以看到有两个Api刚好满足我们的需求:

  1. 根据城市名查询天气(http://apicloud.mob.com/v1/weather/query)

请求方式:GET

请求参数:

名称类型必填说明
keystring用户申请的appkey(可以直接用网站的测试AppKey-520520test)
citystring城市名
provincestring当前城市的所属省市 如:北京-北京-通州、江苏-苏州-吴中(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'}
  1. 城市列表查询接口(http://apicloud.mob.com/v1/weather/citys)

请求方式:GET

请求参数:

名称类型必填说明
keystring用户申请的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': '和县'
            }
          ]
        }
      ]
    }
  ]
}

数据源已经有了,下面整理了需要用到的知识点。

  1. 网络请求-HttpURLConnection

  2. 数据存储-SharedPreference,GreenDao

  3. 后台更新-Service

  4. 多媒体播放-MediaPlayer

  5. 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框架就初始化完毕了。

点赞
收藏
回复
分享
举报
浏览986 编辑于2019-12-03 10:52未知归属地
全部评论
最多点赞
最新发布
最早发布
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。