使用Service+BroadcastReceiver实现定时更新天气
来源:互联网 发布:mysql多表外连接查询 编辑:程序博客网 时间:2024/04/29 05:43
一、前言
最近两个月在做毕业设计:天气app,需要用到定时更新天气数据,用的是Service+BroadcastReceiver方法(之前对服务和广播也不是很了解,所以恶补了一下)。关于这个方法我借鉴了另一篇网络文章点击打开链接。
二、情景描述
2.1 HomeActivity(app启动页,城市天气显示界面)
CityActivity(城市列表界面,跟墨迹天气,天气通一样,就是你选择的城市)
图2.1 侧滑菜单 图2.2 HomeActivity(天气显示) 图2.3 CityActivity
2.2 我们需要实现的是:(1)定时更新城市列表CityActivity中的数据(这些城市天气详细数据都存储在本地SQLite数据库中)。
(2)定时更新主界面HomeActivity中的显示数据(每次打开HomeActivity界面时,显示的是城市列表CityActivity的置顶城市,其实也是从本地数据库中加载显示的)
(3)当APP退出时,定时更新功能仍然有效,可以在后台执行。(注意:有些情况会使得这一功能无效,在文章末尾我会给大家详述)
由于(1)(2)都需要从数据库加载城市天气去显示,所以我们定时更新的时候就直接从数据库一一取出你选择的城市,然后网络请求该城市天气,再存储到本地数据库中,这样就实现了更新本地数据库中城市天气。然后我们再发送一个广播,让CityActivity和HomeActivity接收,继而实现刷新界面显示数据的功能。
三、实现方法
3.1 定时
3.1.1 在app启动页HomeActivity的onCreate方法中设置定时,代码如下:
private void startTimingUpdateService() {// 初次启动服务后,我紧接着设置了一个“闹钟”,一小时后让另一个独立的广播接收器(TimerBroadcastReceiver.java)// 去启动更新天气的服务,从而不必依赖当前的Activity了// 通过闹钟机制30秒后启动服务//静态注册的广播,无论该程序是否启动,都会当广播到来时接收,并处理。Intent intent = new Intent(this, TimerBroadcastReceiver.class);PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, 0);AlarmManager almManager = (AlarmManager) getSystemService(ALARM_SERVICE);almManager.set(AlarmManager.RTC, // RTC 在指定的时刻,发送广播,但不唤醒设备System.currentTimeMillis() + (1000 * 30), pendingIntent);// 30秒}在清单文件AndroidManifest.xml中,静态注册TimerBroadcastReceiver,代码如下:
<receiver android:name="com.eh.erhua_weather.utils.TimerBroadcastReceiver" > </receiver>3.1.2 新建java文件TimerBroadcastReceiver.java,代码如下:
package com.eh.erhua_weather.utils;import android.app.AlarmManager;import android.app.PendingIntent;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.util.Log;/*** @author Administrator* 在这个广播接收器里又设置了一个“闹钟”,30秒后启动自己,然后开启服务,又设置一个周期为一小时的“闹钟”……如此循环,就达到了,周期定时的目的了**/public class TimerBroadcastReceiver extends BroadcastReceiver {private static final String tag = "TimerBroadcastReceiver";@Overridepublic void onReceive(Context context, Intent intent) {Log.d(tag, "广播");intent.setClass(context, UpdateCityWeatherService.class);context.startService(intent);// 通过闹钟机制3秒后启动本广播接收器,实现以后每隔3秒启动本接收器,开启服务Intent intent2 = new Intent(context, TimerBroadcastReceiver.class);PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent2, 0);AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);alarmManager.set(AlarmManager.RTC, // RTC 在指定的时刻,发送广播,但不唤醒设备System.currentTimeMillis() + (1000 * 30), pendingIntent);}}
完成这两步后,就实现了定时,每隔30秒就会循环一次。我们看到在TimerBroadcastReceiver中开启了一个服务UpdateCityWeatherService,我们要在它里面实现具体的天气更新操作。你可能会问:“为什么不直接在广播中执行具体的天气更新操作呢,而是开启服务,去服务中执行”,因为广播中不能执行耗时操作,你可以去百度了解一下相关资料,这里我就不解释了,而且我也是个小白,估计不能给你解释清楚。
3.2 具体的天气更新操作
3.2.1 上面说开启了服务UpdateCityWeatherService,接着我们去清单文件AndroidManifest.xml注册这个服务,代码如下:
<service android:name="com.eh.erhua_weather.utils.UpdateCityWeatherService" > </service>
3.2.2 然后我们新建java文件UpdateCityWeatherService(继承Service),在onCreate方法中开启线程执行具体的天气更新操作,代码如下:
@Overridepublic void onCreate() {super.onCreate();// Log.d(TAG, "onCreate() executed");// 应该在Service中开启线程去执行耗时任务,这样就可以有效地避免ANR(Application Not Responding)的出现。// 先检查网络是否连接,如果有网再执行否则关闭本次更新,等待下一个闹钟if (isNetWorkAvailable()) {// Log.d(TAG, "测试");new Thread(mRunnable).start();}stopSelf();// 发送广播后,停止自己,优化资源}private Runnable mRunnable = new Runnable() {@Overridepublic void run() {// 在此执行具体更新天气操作// 取出本地数据库城市天气中的城市,一个一个地查询保存// 完毕后,通知城市管理界面和主界面,自动刷新// 数据库查询数据--城市天气集合// 创建dao对象cityWeatherDao = new CityWeatherDao(getApplicationContext());CityWeatherList = cityWeatherDao.query();// 判断城市列表是否为空,如果是取消本次更新for (int i = 0; i < CityWeatherList.size(); i++) {// 取出第i个城市,获取最新天气String city = CityWeatherList.get(i).getCity();Log.d(TAG, "开始更新第"+i+"个城市: "+city);try {city = URLEncoder.encode(city, "utf-8");String url = "http://apicloud.mob.com/v1/weather/query?key=1c050b9935858&city=" + city;URL httpUrl;httpUrl = new URL(url);HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();conn.setRequestMethod("GET");conn.setReadTimeout(5000);BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));String str1;StringBuffer sb = new StringBuffer();while ((str1 = reader.readLine()) != null) {sb.append(str1);}Gson gson = new Gson();WeatherDataBean winfo = gson.fromJson(sb.toString(), WeatherDataBean.class);initCityListData(winfo);} catch (Exception e) {}}// 完毕后,通知城市管理界面和主界面,自动刷新Log.d(TAG, "所有城市天气更新完毕");Intent intent = new Intent("android.intent.action.MY_BROADCAST");intent.putExtra("msg", "1");sendBroadcast(intent);}};
我们可以看到在子线程中,当本地数据库城市天气更新完毕后,我发送了一个广播,它的作用就是去通知CityActivity和HomeActivity,这样它们就可以更新界面数据了。
3.2.3 我们先看CityActivity(城市列表界面),我们要在它里面写一个广播接收器,这样才能收到UpdateCityWeatherService中的广播。
首先我们要在onCreate方法里动态注册广播接收器,代码如下:
// 在发送之前,确定在代码的某个位置已经动态注册MyReceiver receiver = new MyReceiver();IntentFilter filter = new IntentFilter();filter.addAction("android.intent.action.MY_BROADCAST");registerReceiver(receiver, filter);
动态注册的程序只有在程序运行时才会收到广播消息,程序不运行了,它就收不到了。因为只有在app运行时,只有在当前一直停留在CityActivity页面时,我们才需要主动刷新
城市管理页面数据,至于你从其他页面切换到CityActivity时,程序会自己从本地数据库加载已经更新好的数据去显示,不需要我们去干预。
3.2.4 然后我们在CityActivity中写一个内部类MyReceiver,代码如下:
public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.MY_BROADCAST")) { String msg = intent.getStringExtra("msg"); //Log.i(tag, "收到广播测试"+msg); if(msg.equals("1")){ //收到广播指令后,重新从数据库加载页面数据 //Log.i(tag, "收到广播测试"+msg); initCityListData(); } } } }
它收到从UpdateCityWeatherService传来的广播,匹配后,就执行initCityListData()来更新CityActivity页面数据。
3.2.5同理,HomeActivity也一样,这里我就不写了,文章末尾会给大家提供我的源码。
四、注意
我在上面有段标红的文字说“当app退出时,定时更新在某些情况下会失效”,下面我就详细给大家说说:
4.1 情景一(测试机:三星 型号:GT-S7898 Android版本4.1.2):
手机上安装“净化大师”的时候,“净化大师”会默认将你的app纳入它的净化范围(它的
“净化设置”->“系统净化”会自动把你app设置为“防止自启和相互唤醒”,“智能回收后台进程”)。
此时我们运行APP:
图4.1 APP处于运行状态(定时更新运行正常)
图4.2 APP退出,被关闭(发现从23:22:01到23:25及其以后的时间,没有执行定时更新)
当我们在“净化大师”去掉对该APP的设置后,允许其自启,再次运行APP并退出程序,见图4.3
图4.3 打开APP再退出(因为你要运行启动页Activity才能启动定时更新)
会发现,此时当退出APP时,定时更新仍然有效。
4.2 情景二(测试机:贝尔丰Bifer 型号BF_T13)
该测试机有个自带的“安全中心”,在里面有“手机加速”->“受保护应用”“自启动管理”将你
当前APP勾选住,运行启动页后再退出APP,发现定时更新仍然可用。反之,在“安全中心”取消刚才对APP的设置,你会
发现在退出APP后,定时更新不可用。
总结,如果你手机出现上述该类情况,使得定时更新不可用,就看看是哪个应用限制了APP的后台运行。
五、源码
5.1 为了方便大家能更好的理解,我将我正在做的毕业设计源代码提供给大家,仅供学习参考。源码地址:点击打开链接(即
http://download.csdn.net/download/qq_24933841/9828926)
5.2 我也是个小白,可能文章讲的不是那么好,欢迎大家批评指正。
- 使用Service+BroadcastReceiver实现定时更新天气
- Android学习笔记--Service+BroadcastReceiver实现动态更新UI和定时更新UI (如时间和天气预报)
- 15/9/8/BroadcastReceiver实现定时功能/Service
- 通过aAlarmmanger、Service、BroadcastReceiver实现定时访问任务
- android之后台定时更新ui天气【Timer、service、broadcast、activity】
- Android~Service+BroadcastReceiver使用
- android AppWidget的使用以及利用Service TimerTask实现widget的定时更新
- 使用BroadcastReceiver实现开机启动Service或Activity
- 使用BroadcastReceiver实现开机启动Service或Activity
- 使用BroadcastReceiver实现开机启动Service或Activity
- 使用BroadcastReceiver实现开机启动Service或Activity
- android 使用BroadcastReceiver实现开机启动Service或Activity
- 使用BroadcastReceiver实现开机启动Service或Activity
- 【Android应用实例之四】计时器之通过Service&BroadcastReceiver实现UI动态更新
- 【Android应用实例之四】计时器之通过Service&BroadcastReceiver实现UI动态更新
- 使用ASP.NET实现Windows Service定时执行任务
- 使用ASP.NET实现Windows Service定时执行任务
- 使用ASP.NET实现Windows Service定时执行任务
- LeetCode-287. Find the Duplicate Number (JAVA)寻找重复元素
- 基于proteus的51单片机仿真实例七、关于proteus和keil c51的联调
- 微信实验十四、ThinkPHP5.0用户批量删除及源码下载
- 收藏的数据结构工程
- 基于proteus的51单片机仿真实例八、关于proteus常用操作的补充说明
- 使用Service+BroadcastReceiver实现定时更新天气
- 树的直径,树的重心以及树的分治
- Android APN的设置问题 默认“已起用数据” 关闭
- Maxwell
- you-get遇到的坑
- C++之逗号运算符
- EmguCv初接触
- Python自动化脚本【1】url提取及自动打开页面
- 基于proteus的51单片机仿真实例九、51单片机的最小工作系统