自己实现简单的天气预报应用(8)

8.加入服务来实现自动更新和时钟功能

新建一个服务类,通过发送Intent来通知AppWidgetProvider:

  1 import android.app.AlarmManager;
  2 import android.app.IntentService;
  3 import android.app.PendingIntent;
  4 import android.content.Context;
  5 import android.content.Intent;
  6 import android.net.ConnectivityManager;
  7 import android.widget.Toast;
  8
  9 import com.android.volley.Request;
 10 import com.android.volley.RequestQueue;
 11 import com.android.volley.Response;
 12 import com.android.volley.VolleyError;
 13 import com.android.volley.toolbox.JsonObjectRequest;
 14 import com.android.volley.toolbox.Volley;
 15
 16 import org.json.JSONException;
 17 import org.json.JSONObject;
 18
 19 import java.io.File;
 20 import java.io.IOException;
 21 import java.util.ArrayList;
 22
 23 public class UpdateService extends IntentService {
 24
 25     //这个是用来后台更新数据的,就是只是检查有无新数据的
 26
 27     private static final String TAG="UpdateService";
 28     private static final String url="http://api.k780.com:88/?app=weather.future&weaid=101270101&appkey=13217&sign=efb0ccae3443e25fe2238e5bb2f83bba&format=json";
 29     private static final int WEATHER_ALARM_CLOCK=3600000;
 30
 31     private static File configure;
 32     private static boolean hasNew;
 33     private static ArrayList<WeatherItem> weatherItems=new ArrayList<>();
 34
 35     public UpdateService() {
 36         super(TAG);
 37         hasNew=false;
 38     }
 39
 40     public static void setServiceAlarm(Context context,boolean isOn){
 41         Intent intent=new Intent(context,UpdateService.class);
 42         PendingIntent pi=PendingIntent.getService(context,0,intent,0);
 43         AlarmManager alarmManager=(AlarmManager)context.getSystemService(ALARM_SERVICE);
 44         if(isOn){
 45             alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), WEATHER_ALARM_CLOCK, pi);
 46         }else {
 47             alarmManager.cancel(pi);
 48             pi.cancel();
 49         }
 50     }
 51
 52     @Override
 53     protected void onHandleIntent(Intent intent) {
 54         ConnectivityManager cm=(ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
 55         boolean isNetWorkAvailable=cm.getBackgroundDataSetting() && cm.getActiveNetworkInfo()!=null;
 56         if(!isNetWorkAvailable){
 57             return;
 58         }
 59         configure=new File(getFilesDir()+"/"+FileTools.conf);
 60         update();
 61         Intent i=new Intent();
 62         i.setAction(WeatherWidgetProvider.UPDATE_DATA);
 63         sendBroadcast(i);
 64     }
 65
 66     private void update(){
 67
 68         if(!configure.exists()){
 69             Toast.makeText(getApplicationContext(), R.string.fetching, Toast.LENGTH_SHORT).show();
 70             fetchData();
 71         }else{
 72             try{
 73                 hasNew = !(DateTools.getDate().equals(FileTools.loadConf(getApplicationContext())));
 74             }catch (IOException e){
 75                 e.printStackTrace();
 76             }
 77             if(hasNew){
 78                 Toast.makeText(getApplicationContext(),R.string.fetching,Toast.LENGTH_SHORT).show();
 79                 fetchData();
 80             }
 81         }
 82     }
 83
 84     private void fetchData(){
 85         RequestQueue mQueue= Volley.newRequestQueue(getApplicationContext());
 86         mQueue.add(new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
 87             @Override
 88             public void onResponse(JSONObject jsonObject) {
 89                 //服务器有响应的时候才会调用此方法
 90                 try {
 91                     weatherItems = ParseTools.getInstance(jsonObject.toString(),ParseTools.REQUEST_RAW);
 92                     //保存数据到文件
 93                     FileTools.saveData(getApplicationContext(),weatherItems);
 94                     Toast.makeText(getApplicationContext(),"更新完毕",Toast.LENGTH_SHORT).show();
 95                     FileTools.saveWidgetData(getApplicationContext(), weatherItems.get(0));
 96                 } catch (JSONException | IOException e) {
 97                     e.printStackTrace();
 98                 }
 99             }
100         }, new Response.ErrorListener() {
101             @Override
102             public void onErrorResponse(VolleyError volleyError) {
103                 Toast.makeText(getApplicationContext(), "获取失败", Toast.LENGTH_SHORT).show();
104             }
105         }));
106         mQueue.start();
107     }
108
109     @Override
110     public void onDestroy() {
111         super.onDestroy();
112     }
113 }

然后onReceive接受:

 1 import android.appwidget.AppWidgetManager;
 2 import android.appwidget.AppWidgetProvider;
 3 import android.content.ComponentName;
 4 import android.content.Context;
 5 import android.content.Intent;
 6 import android.text.format.DateFormat;
 7 import android.widget.RemoteViews;
 8
 9 import org.json.JSONException;
10
11 import java.io.IOException;
12 import java.util.Date;
13
14 //管理所有Widget的类
15 @SuppressWarnings("NullableProblems")
16 public class WeatherWidgetProvider extends AppWidgetProvider {
17
18     public static final String UPDATE_DATA="action.appwidget.SEND_DATA";
19     public static final String UPDATE_TIME="action.appwidget.UPDATE_TIME";
20     private static WeatherItem mItem;//这里必须使用静态成员
21
22     @Override
23     public void onReceive(Context context, Intent intent) {
24         RemoteViews rv=new RemoteViews(context.getPackageName(),R.layout.widget_layout);
25         AppWidgetManager appWidgetManager=AppWidgetManager.getInstance(context);
26         ComponentName componentName=new ComponentName(context,WeatherWidgetProvider.class);
27         int[] appWidgetIds=appWidgetManager.getAppWidgetIds(componentName);
28         switch (intent.getAction()){
29             case UPDATE_DATA:
30                 for(int appWidgetId : appWidgetIds){
31                     rv.setTextViewText(R.id.date, mItem.getDate());
32                     rv.setTextViewText(R.id.week,mItem.getWeek());
33                     rv.setTextViewText(R.id.weather,mItem.getWeather());
34                     rv.setTextViewText(R.id.temp,mItem.getTemp_low() + "~" + mItem.getTemp_high() + "℃");
35                     rv.setTextViewText(R.id.wind,mItem.getWind());
36                     appWidgetManager.updateAppWidget(appWidgetId,rv);
37                 }
38                 break;
39             case UPDATE_TIME:
40                 for(int appWidgetId : appWidgetIds){
41                     rv.setTextViewText(R.id.time, DateFormat.format("kk:mm",new Date()));
42                     appWidgetManager.updateAppWidget(appWidgetId,rv);
43                 }
44                 break;
45         }
46         super.onReceive(context, intent);
47     }
48
49     @Override
50     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
51         RemoteViews rv;
52         try{
53             mItem = FileTools.loadWidgetData(context);
54         }catch (IOException | JSONException e){
55             e.printStackTrace();
56         }
57         if(mItem != null){
58             rv = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
59             rv.setTextViewText(R.id.date,mItem.getDate());
60         }else{
61             rv = new RemoteViews(context.getPackageName(),R.layout.widget_void_layout);
62         }
63
64         for(int appWidgetId : appWidgetIds){
65             appWidgetManager.updateAppWidget(appWidgetId,rv);
66         }
67         super.onUpdate(context, appWidgetManager, appWidgetIds);
68     }
69
70     @Override
71     public void onEnabled(Context context) {
72         super.onEnabled(context);
73         TimeService.setTimeAlarm(context,true);
74         UpdateService.setServiceAlarm(context,true);
75     }
76
77     @Override
78     public void onDisabled(Context context) {
79         super.onDisabled(context);
80         TimeService.setTimeAlarm(context,false);
81         UpdateService.setServiceAlarm(context,false);
82     }
83 }

这里面有一个实现时钟功能的Service:

 1 import android.app.AlarmManager;
 2 import android.app.IntentService;
 3 import android.app.PendingIntent;
 4 import android.content.Context;
 5 import android.content.Intent;
 6
 7 public class TimeService extends IntentService {
 8     private static final String TAG="TimeService";
 9     private static final int TIME_ALARM_CLOCK=1000;
10
11     public TimeService() {
12         super(TAG);
13     }
14
15     public static void setTimeAlarm(Context context, boolean isOn){
16         Intent intent=new Intent(context,TimeService.class);
17         PendingIntent pi=PendingIntent.getService(context,0,intent,0);
18         AlarmManager alarmManager=(AlarmManager)context.getSystemService(ALARM_SERVICE);
19         if(isOn){
20             alarmManager.setRepeating(AlarmManager.RTC,System.currentTimeMillis(),TIME_ALARM_CLOCK,pi);
21         }else{
22             alarmManager.cancel(pi);
23             pi.cancel();
24         }
25     }
26
27     @Override
28     protected void onHandleIntent(Intent intent) {
29         Intent i = new Intent();
30         i.setAction(WeatherWidgetProvider.UPDATE_TIME);
31         sendBroadcast(i);
32     }
33 }

当然这些数据必须要在manifest中定义节点:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="                                " >
 4
 5     <uses-permission android:name="android.permission.INTERNET"/>
 6     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 7
 8     <application
 9         android:allowBackup="true"
10         android:icon="@drawable/ic_launcher"
11         android:label="@string/app_name"
12         android:theme="@style/AppTheme" >
13         <activity
14             android:name=".MainActivity"
15             android:label="@string/app_name" >
16             <intent-filter>
17                 <action android:name="android.intent.action.MAIN" />
18
19                 <category android:name="android.intent.category.LAUNCHER" />
20             </intent-filter>
21         </activity>
22
23         <receiver android:name=".WeatherWidgetProvider" android:label="@string/weather">
24             <intent-filter>
25                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
26                 <action android:name="action.appwidget.SEND_DATA"/>
27                 <action android:name="action.appwidget.UPDATE_TIME"/>
28             </intent-filter>
29             <meta-data android:name="android.appwidget.provider"
30                 android:resource="@xml/widget_info"/>
31         </receiver>
32         <service android:name=".UpdateService"/>
33         <service android:name=".TimeService"/>
34     </application>
35 </manifest>

所有这些东西完成之后Widget效果如下,测试的过程中还是有些Bug:

所有的东西就是这样的,github地址:https://github.com/wylhyz/TimeAndWeather

时间: 2024-10-01 06:02:14

自己实现简单的天气预报应用(8)的相关文章

阶段一:一个简单的天气预报应用的完整实现过程(一)

“阶段一”是指我第一次系统地学习Android开发.这主要是对我的学习过程作个记录. 在上一篇阶段一:解析JSON中提到,最近在写一个很简单的天气预报应用.即使功能很简单,但我还是想把它做成一个相对完整的应用.这样的话,像以前想到什么就做什么,显然是不行的,很容易就乱了.所以我就琢磨了一下,弄个什么,让自己的思路变得更加清晰,仅此而已. 经过一些思考和总结之后,我觉得可以是这么一个流程: 第一步:想好这个应用要实现什么功能,并罗列出来,然后就开始写代码,实现这些功能 说明:(1)对于这个模型的具

WP8.1开发:简单的天气预报应用

今天小梦给大家分享一个简单的天气预报应用源码:调用的是百度API.整个应用都没有什么难点.只是一个简单的网络请求和json数据处理.在WP8.1有小娜的情况下,天气预报应用还有意义吗?我认为还是有点意义的,至少数据更详细,而要想要用户喜欢,必须有比小娜更人性化的提醒和精美的UI.UI必须要精美.当然小梦今天分享的UI很简单.大家可以根据自己的想象去处理UI.之所以分享出来,是分享JSON的数据处理.在WP8.1开发XML读取中央气象城市代码文件中,分享了XML文件和JSON数据解析的方法,不过其

.net请求Webservice简单实现天气预报功能

很久没有接触Webservice的知识,今天稍微复习了一下关于webservice,简单做了一个天气预报的功能,虽然界面丑的厉害,但功能算是实现了,以下是效果展示. 这东西没什么难点,只是天气预报的功能在网站类的开发中会经常用到,所以就简单写下,以便以后查阅. 1.新建一个网站或者web应用程序,添加一个aspx页面,用于展示天气数据.(这个应该不用细讲吧) 2.在网上找一个免费的天气预报的接口,我用的是Webxml网站的,地址如下: http://webservice.webxml.com.c

Python 简单的天气预报

轻巧的树莓派一直是大家的热爱,在上面开发一些小东西让我们很有成就感,而在linux下,python能使麻烦的操作变得简单,而树莓派功耗还很低,相结合,完美! 1,直接进入正题,一般在linux或树莓派的raspberry的系统下会自动安装好python,而我们还需要python下的一个模块叫做requests,他需要pip安装,所以我们首先要安装pip curl -O https://bootstrap.pypa.io/get-pip.py python get-pip.py 2,安装好后安装r

自己实现简单的天气预报应用(6)

6.加入Widget小部件 由于小部件的存在,我们可以直接在启动器上查看某些数据,下面通过一个简单布局Widget的实现学习如何与Widget的Provider类通信,和如何用外部传入的数据初始化Widget, 首先,按照编写小部件的标准步骤,定义布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.

自己实现简单的天气预报应用(1)

记录一下我自己实现的一个天气预报应用的过程,这不是一个已经完成的应用,每次写下的都是实现的一个阶段,每个阶段解决一个问题. 1.获取天气预报的json数据 由于是在不想使用xml,在晚上查了很久才查到了一个可以用的返回json的天气预报请求http 这就是 http://www.k780.com/api/weather.future 构建的示例这个页面上已经给出: http://api.k780.com:88/?app=weather.future&weaid=1&appkey=10003

自己实现简单的天气预报应用(2)

2.设计模型层 从上一篇中获得的天气预报情况类似这样: { "temp_low": "7", //最低温度 "cityno": "chengdu", "wind": "北风", //风向 "citynm": "成都", //城市/地区 "weaid": "265", "winpid": &

简单的天气预报Demo

一.需求 选择城市获得相应城市最近几天的天气预报 数据源: 1.全国城市列表xml -----http://yunpan.cn/cmMA5DrFeM4m6 (提取码:ccb1) 2.天气json数据源 http://weather.xcyh.org/101210401/json/6   101210401部分为城市的编号 二.设计思路 三个下拉列表 分别显示省.市.县的名字,一个按钮 为查询   一个ListView显示最近该城市几天的天气预报 xml解析获取城市名称集合,json解析获取天气

自己实现简单的天气预报应用(7)

7.从文件中加载数据,取消Intent消息传递 解决上一篇最后提出问题的一种思路如下: 在程序每次fetch数据的时候同步将当天气象数据写入一个文件中供widget调用,每次更新Widget的时候都从文件中加载数据, 修改的数据如下: 在解析工具类中加入一个方法: public static WeatherItem parseItem(String itemData) throws JSONException{ JSONObject object = (JSONObject) new JSONT

自己实现简单的天气预报应用(4)

4.数据的本地存储 从网络上获取的我称之为原始数据,解析之后保存的称为item数据,下面修改解析工具类来分别按照请求码来进行解析: 1 import org.json.JSONArray; 2 import org.json.JSONException; 3 import org.json.JSONObject; 4 import org.json.JSONTokener; 5 6 import java.util.ArrayList; 7 8 public class ParseTools {