来源:网易云课堂GeekBand第七次作业

作业要求:

做一个天气应用

  1. 接口参考: http://apistore.baidu.com/apiworks/servicedetail/880.html,只是参考API,可自行查找使用其他API接口
  2. 考察内容:获取数据,解析JSON
  3. 数据缓存在数据库中,使用ContentProvider来处理
  4. 如果不强制刷新,则使用缓存数据每隔一定时间再刷新一次

前期准备

1.选择合适的API!选择合适的API!选择合适的API!(重要的话说三遍,中途变更API严重影响效率和心情).

2.gson.如何添加依赖库 http://www.cnblogs.com/happyhacking/p/5257002.html

目录结构

UI

注意:在布局的过程中weightSum和layout_weight要慎用,尤其是在内容长度可变的情况下,使用结果往往不符合预期.

主要逻辑

主要逻辑集中在查询按钮的点击事件上

(注意:cursor.moveToFirst(),Long.valueOf()和Long.getLong()的用法.)

 mQueryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//判断用户是否输入了城市名称
if (!TextUtils.isEmpty(mCityName.getText())) {
//首先查询本地数据库
Uri uri = Uri.parse("content://com.example.janiszhang.weatherdemo.provider/weatherdata");
Cursor cursor = getContentResolver().query(uri, null, "cityname = ?", new String[]{mCityName.getText() + ""}, null);
if (cursor.moveToFirst()) {// 查询成功 //这里不可以使用cursor!= null来判断!!!!
Log.i("zhangbz", cursor.getString(cursor.getColumnIndex("savetime"))); if ((System.currentTimeMillis() - Long.valueOf(cursor.getString(cursor.getColumnIndex("savetime")))) < (1000*60)) {//这里不可以使用Long.getLong(),因为它返回的是系统属性的值,其参数是被请求的系统属性的名称
//如果数据库中的数据没有过期,就从数据库中查询
updateUIfromDatabase(cursor);
} else {
//如果数据库中的数据过期了,则通过网络查询并update到数据库
shouldUpdate = true;
try {
httpArg = "city=" + URLEncoder.encode(mCityName.getText().toString(), "UTF-8");//中文需要编码
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
new MyAsyncTask().execute(httpArg);//使用asynctask }
} else {
//网络查询并insert到数据库
shouldUpdate = false;//需要insert
try {
httpArg = "city=" + URLEncoder.encode(mCityName.getText().toString(), "UTF-8");//中文需要编码
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
new MyAsyncTask().execute(httpArg);
} SharedPreferences sp = getSharedPreferences("last", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("cityname", mCityName.getText().toString());
editor.apply(); //开启自动更新
Intent intent = new Intent(MainActivity.this, AutoUpdateService.class);
startService(intent);
}
}
});

重点记录

使用Gson解析数据

            Gson gson = new Gson();
WeatherDataStatus weatherDataStatus = gson.fromJson(s, WeatherDataStatus.class);

这里注意两个问题:

1.使用gson解析json数据时,不需要为整个json数据创建实体类,只需要为需要解析的数据定义变量和提供getter/setter方法.

2.注意区分什么是json数组:

        //json数组:中括号
[{
"这是json数组": "这是json数组"
}, {
"这是json数组": "这是json数组"
}, {
"这是json数组": "这是json数组"
}] //注意和这种情况区分开
{
"这不是json数组": [{
"这才是json数组": "这才是json数组"
}, {
"这才是json数组": "这才是json数组"
}, {
"这才是json数组": "这才是json数组"
}]
}

自动更新的实现

service需要由Activity启动,之后由service和receiver配合相互唤醒.

AutoUpdateService.class

public class AutoUpdateService extends Service{

    private String mCityname;

    @Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
//在子线程中发起网络请求,将请求结果保存到数据库中
new Thread(new Runnable() {
@Override
public void run() {
updateWeather();
}
}).start(); //使用AlarmManager实现定时任务
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 8 * 60 *60 * 1000;//8小时
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
//service -> receiver
Intent i = new Intent(this, AutoUpdateReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi); return super.onStartCommand(intent, flags, startId);
}
//... }

AutoUpdateReceiver.class

public class AutoUpdateReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//receiver->service
Intent i = new Intent(context, AutoUpdateService.class);
context.startService(i);
}
}

contentprovider的练习

虽然用在这里很牵强,但是目的是练习嘛.

很久没有使用contentprovider,以下为基本使用方法.

public class MyProvider extends ContentProvider{

    public static final int WEATHERDATA_DIR = 0;
public static final String AUTHORITY = "com.example.janiszhang.weatherdemo.provider";
private static UriMatcher sUriMatcher;
private MyDBHelper mMyDBHelper; static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(AUTHORITY, "weatherdata", WEATHERDATA_DIR);
}
@Override
public boolean onCreate() {
mMyDBHelper = new MyDBHelper(getContext(), "weatherDataDB.db", null, 1);
return true;
} @Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = mMyDBHelper.getReadableDatabase();
Cursor cursor = null;
switch (sUriMatcher.match(uri)) {
case WEATHERDATA_DIR:
cursor = db.query("weatherdata", projection, selection, selectionArgs, null, null, sortOrder);
break;
}
return cursor;
} @Nullable
@Override
public String getType(Uri uri) {
switch (sUriMatcher.match(uri)) {
case WEATHERDATA_DIR:
return "vnd.android.cursor.dir/vnd.com.example.janiszhang.weatherdemo.provider.weatherdata";
}
return null;
} @Nullable
@Override
public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mMyDBHelper.getReadableDatabase();
Uri uriReturn = null;
switch (sUriMatcher.match(uri)) {
case WEATHERDATA_DIR:
long newId = db.insert("weatherdata", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/weatherdata/" + newId);
break;
}
return uriReturn;
} @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
} @Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = mMyDBHelper.getWritableDatabase();
int updateRows = 0;
switch (sUriMatcher.match(uri)) {
case WEATHERDATA_DIR:
updateRows = db.update("weatherdata", values, selection, selectionArgs);
break;
}
return updateRows;
}
}

github地址:https://github.com/zhangbz/WeatherDemo

总结:写这个demo,把四大组件都用到了,把基本用法复习了一遍,温故知新.

android开发练习:天气应用的更多相关文章

  1. Android经典项目开发之天气APP实例分享

    原文:Android经典项目开发之天气APP实例分享 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/mzc186/article/details/5 ...

  2. 50个Android开发人员必备UI效果源码[转载]

    50个Android开发人员必备UI效果源码[转载] http://blog.csdn.net/qq1059458376/article/details/8145497 Android 仿微信之主页面 ...

  3. 【Mood-12】Android开发相关书籍推荐

    新年伊始,找到Android进阶干货若干,2015拜读. 1.Android应用UI设计模式 目前,谷歌Android操作系统在移动市场中风头正劲,并且未来发展势不可挡.<Android应用UI ...

  4. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

  5. Android开发心得(转)

    前言: 很早以前,就听人说过android以后会火起来,作为一个前瞻性对它有所了解会是一个转型的好机会,javaweb太成熟饱和了,现在市面上各种android手机层出不穷,网上各种android视频 ...

  6. Android解析中国天气网的Json数据

    在Android开发中.一般的APP都是通过获取server端的数据来更新UI.从server获取到的数据能够是Json.它的数据量要比XML要小,这里解析中国天气网上获取的数据,尽管已经不再更新了. ...

  7. Android开发周报:反编译对抗研究、动手制作智能镜子

    新闻 <Android Wear落地中国 谷歌增强安卓生态控制力> :9月8日,由摩托罗拉推出的智能手表Moto 360二代作为国内发售的第一款搭载官方Android Wear的设备,正式 ...

  8. Android开发周报:Android L默认加密用户数据

    Android开发周报:Android L默认加密用户数据 新闻 <iCloud前车之鉴,Android L默认开启加密功能>:iCloud 艳照风波再起,第二波女星照片流出,大量女星的裸 ...

  9. Android开发10:传感器器及地图相关应用

    前言 啦啦啦~各位小伙伴们好~经过这一学期的Android知识的学习,我们学到了很多和Android开发相关的知识,这一学期的学习也要告一段落了. 一起进入我们今天的相关内容~这次我们将一起学习使用 ...

随机推荐

  1. 递归查询树形结构的SQL

    最近项目中要递归树形,案例如下: 测试数据: ),PID ),Name )) ',NULL ,'山东省' ','烟台市' ','招远市' ','青岛市' ',NULL ,'四会市' ','清远市' ' ...

  2. 基于MVC4+EasyUI的Web开发框架经验总结(15)--在MVC项目中使用RDLC报表

    RDLC是一个不错的报表,有着比较不错的设计模式和展现效果,在我的Winform开发里面,使用RDLC也是一个比较方便操作,如可以参考文章<DevExpress的XtraReport和微软RDL ...

  3. Ubuntu Server 16.04下ASP.NET Core Web Api + MySql + Dapper在 Jexus、nginx 下的简单测试

    一.环境及工具 1.服务器 VirtualBox5.1.4 安装 Ubuntu Server 16.04 amd64 MySql Ver 14.14 Distrib 5.6.21 Jexus 5.8. ...

  4. Lua使用心得(1)

    这几天研究了一下lua,主要关注的是lua和vc之间的整合,把代码都写好放在VC宿主程序里,然后在lua里调用宿主程序的这些代码(或者叫接口.组件,随便你怎么叫),希望能用脚本来控制主程序的行为.这实 ...

  5. Java工程图标前面的红色叹号

    有时Java工程图标前面会出现一个红色的叹号,这是因为工程引入的jar包不存在(或者被删除.移动)造成的. 右键点击工程,选择Build Path->Configure Build Path,弹 ...

  6. 禅道 Rest API 开发

    在老的 PHP 系统中使用 PHP 5.3以后的库 所谓老的系统,是指没有使用PHP 5.3以上命名空间(namespace)特性编码的系统. 但是,只要你的系统运行在 PHP 5.3及以上的环境,在 ...

  7. @media自适应宽度

    <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name ...

  8. [Cordova] 无法显示Alert视窗

    [Cordova] 无法显示Alert视窗 问题情景 今天开了一个Cordova专案做范例,将预设的index.html页面修改为下列内容.按下执行却发现,这样一个简单的范例无法正常执行.点击页面上的 ...

  9. C# 中几个小“陷阱”

    每天写代码,偶尔就会有让你抓狂的时候:代码改了千百遍,蓦然回首,Bug就在灯火阑珊处……这里就列举一些容易犯错的几个小地方,以后遇到了其他的,再慢慢添加.   1. 获取程序当前运行路径   情景复现 ...

  10. Code First :使用Entity. Framework编程(4) ----转发 收藏

    第4章 对关系使用默认规则与配置 在第3章,你已经掌握了默认规则与配置对属性以及其在数据库映射的字段的影响.在本章,我们把焦点放在类之间的关系上面.这包括类在内存如何关联,还有数据库中的外键维持等.你 ...