地震信息WIDGET
地震简介:
英文:earthquake
地球可分为三层。中心层是地核;中间是地幔;外层是地壳。地震一般发生在地壳之中。地壳内部在不停地变化,由此而产生力的作用(即内力作用),使地壳岩层变形、断裂、错动,于是便发生地震。超级地震指的是震波极其强烈的大地震。但其发生占总地震7%~21%,破坏程度是原子弹的数倍,所以超级地震影响十分广泛,也是十分具破坏力。
地震是地球内部介质局部发生急剧的破裂,产生的震波,从而在一定范围内引起地面振动的现象。地震(earthquake)就是地球表层的快速振动,在古代又称为地动。它就像海啸、龙卷风、冰冻灾害一样,是地球上经常发生的一种自然灾害。 大地振动是地震最直观、最普遍的表现。在海底或滨海地区发生的强烈地震,能引起巨大的波浪,称为海啸。地震是极其频繁的,全球每年发生地震约550次.
主要功能:
该WIDGET主要功能用于从地震信息网上获取当天的或者一段时间内的世界各地的震信息,并在地图上表示出来。
代码介绍:
既然要显示全国或者世界的地震信息,那么我们必须有一个数据源,网上地震信息发布的网站非常多,大家可以去找找看自己合适的,或者用我提供给大家的几个数据源,这些数据源大多都是国外地震信息的,当然也有全球的。
列表如下:
1.KMZ格式
http://maps.google.com/?q=http://www.gearthblog.com/kmfiles/UKearthquake.kmz
KMZ是Google Earth的文件格式.
KML服务有两种,一种是纯文本的XML,一种是将一个纯文本的XML文件和其他资源(如图标)进行zip压缩后形成的KMZ,本质是zip。使用Android解析KML服务需要根据情况首先判断是否需要解压缩,然后再解析XML文本。
Android Java中包含了zip压缩解压缩工具库,可以从“java.util.zip”包中进行调用。我们看一下一个KMZ如何被解压缩:
代码片段如下:
Code
1 String strUrl="http://maps.google.com/?q=http://www.gearthblog.com/kmfiles/UKearthquake.kmz";
2
3 URL url = new URL(strUrl);
4 HttpURLConnection uc = (HttpURLConnection) url.openConnection();
5
6 InputStream isKxml = null;
7
8 ZipInputStream zipIs = new ZipInputStream(uc.getInputStream());
9 ZipEntry zipEntry = null;
10 while ((zipEntry = zipIs.getNextEntry()) != null)
11 {
12 String zipEntryName = zipEntry.getName();
13 if (zipEntryName.endsWith("kml"))
14 {
15 ByteArrayOutputStream os = new ByteArrayOutputStream();
16 byte[] b = new byte[512];
17 int readedByteSize = 0;
18 while ((readedByteSize = zipIs.read(b)) > 0)
19 {
20 os.write(b, 0, readedByteSize);
21 }
22 os.flush();
23 os.close();
24
25 isKxml = new ByteArrayInputStream(os.toByteArray());
26 }
27 else if (zipEntryName.endsWith("png"))
28 {
29 ByteArrayOutputStream os = new ByteArrayOutputStream();
30 byte[] b = new byte[512];
31 int readedByteSize = 0;
32 while ((readedByteSize = zipIs.read(b)) > 0)
33 {
34 os.write(b, 0, readedByteSize);
35 }
36 os.flush();
37 os.close();
38
39 InputStream isBitmap = new ByteArrayInputStream(os
40 .toByteArray());
41 Bitmap bitmap = BitmapFactory.decodeStream(isBitmap);
42 kml.addBitmap(zipEntryName, bitmap);
43 isBitmap.close();
44 }
45 }
46 zipIs.close();
47
48 Reader reader = new InputStreamReader(isKxml);
49 parseKxml(kml, reader);//解析KML文本的方法
50 isKxml.close();
51 reader.close();
好了,解压缩完成后,重点就在解析KML文本上了。到这里,KMZ其实就是一个XML文件了,我们可以用SAX, XmlDocument, XmlPullParser方法来解析,这些解析的方法网上已经有了很多教程了,我就不多说,这里只用XmlDocument, XmlPullParser两个例子来说名如何解析.
XmlDocument:
Code
1 private static void parseKxml(Kml kml, Reader reader) throws Exception
2 {
3 KXmlParser kXmlParser = new KXmlParser();
4 kXmlParser.setInput(reader);
5 Document doc = new Document();
6 doc.parse(kXmlParser);
7
8 if (doc == null) return;
9
10 Element eRoot = doc.getRootElement();
11 ……(处理XML Element)
12 }
XmlPullParser:
Code
1 private static void parseKxml(Kml kml, Reader reader) throws Exception
2 {
3 // create XML pull parser
4
5 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
6
7 line = getXML(body);
8
9 parser.setInput(new StringReader(line));
10
11 ……(处理XML Element)
12 }
2.XML
这个网站专门提供世界地震信息的http://earthquake.usgs.gov/eqcenter/catalogs/
http://earthquake.usgs.gov/eqcenter/catalogs/1day-M2.5.xml这个XML是即时的世界地震信息,我们只需要隔一段时间取一次就行,XML的解析就不多说了,上面已经说明,或者去网上搜,也有很多方式来解析XML.通过解析这些XML可以获得我们所需要的地震信息,然后我们呈现给用户就行了。
3.国内网站
http://www.ceic.ac.cn/ceic/index.jsp
可以通过解析网页得到最新的地震信息
http://www.ceic.ac.cn/ceic/eq.jsp?id=107917
该网站的传值方式很简单,利用ID来传值,我们就可以利用这个,然后放在WebView呈现给用户.
4.取图片方式
因为在我找的数据源中是由一个gif图片组成的一段时间内地震的情况
http://www.iris.edu/seismon/views/eveday//imgs/topMap.eveday.gif
这是这个GIF图,这个图显示的是一段时间内世界上所有地区的地震情况.
http://www.iris.edu/seismon/imgs/top_legend.gif 这个是解释的一段时间的地震图,最好在左上角显示出来.
如何实现我给个思路,我们用相对布局RelativeLayout,然后在这个布局上面放置一个ImageView,这个ImageView的BG用http://www.iris.edu/seismon/views/eveday//imgs/topMap.eveday.gif
这个图就成了我们的背景,然后我们再在这个imgView上放置一个ImgView,这样就可以将topMap放到toplegend上面了,例子如下..
Code
1 <?xml version="1.0" encoding="utf-8"?>
2
3 <RelativeLayout android:id="@+id/widgdd"
4
5 xmlns:android="http://schemas.android.com/apk/res/android"
6
7 android:layout_width="wrap_content" android:layout_height="120px">
8
9
10
11 <ImageView android:id="@+id/Einstein_Quote_Of_The_Day_ImageView01"
12
13 android:background="@drawable/widget_einsteinquoteoftheday_bg"
14
15 android:layout_marginTop="10px"
16
17 android:layout_width="310px" android:layout_height="80px">
18
19 </ImageView>
20
21 <TextView android:layout_width="wrap_content"
22
23 android:layout_height="wrap_content"
24
25 android:text="@string/einsteinquoteoftheday_Widget_Title"
26
27 android:layout_marginLeft="80px"
28
29 android:textSize="12px" android:id="@+id/einsteinquoteoftheday_Widget_Title" android:layout_marginTop="17px" android:textColor="#ffffff"/>
30
31 <ImageButton android:id="@+id/einsteinquoteoftheday_btnSetting"
32
33 android:background="@drawable/widget_einsteinquoteoftheday_imgbut3"
34
35 android:minHeight="100px" android:minWidth="100px" android:layout_width="48px" android:layout_height="48px" android:layout_marginLeft="270px" android:layout_marginTop="10px">
36
37 </ImageButton>
38
39 <ImageView android:id="@+id/einsteinquoteoftheday_ImgBack"
40
41 android:layout_below="@id/einsteinquoteoftheday_btnSetting"
42
43 android:layout_height="48px" android:layout_width="48px" android:layout_marginLeft="90px" android:layout_marginTop="10px">
44
45 </ImageView>
46
47 <ImageView android:id="@+id/einsteinquoteoftheday_ImgNext"
48
49 android:layout_below="@id/einsteinquoteoftheday_btnSetting"
50
51 android:layout_marginLeft="162px" android:layout_height="48px" android:layout_width="48px" android:layout_marginTop="10px">
52
53 </ImageView>
54
55 <TextView android:id="@+id/einsteinquoteoftheday_TvContent"
56
57 android:layout_width="wrap_content"
58
59 android:layout_height="wrap_content" android:layout_marginLeft="12px"
60
61 android:textSize="10dip" android:textColor="#ffffff"
62
63 android:layout_marginTop="35px" android:maxWidth="270px">
64
65 </TextView>
66
67
68 <ImageView android:id="@+id/einsteinquoteoftheday_ImgMiagc"
69
70 android:layout_below="@id/einsteinquoteoftheday_btnSetting"
71
72 android:background="@drawable/widget_einsteinquoteoftheday_next" android:layout_height="48px" android:layout_width="48px" android:layout_marginLeft="260px" android:layout_marginTop="10px">
73
74 </ImageView>
75
76 </RelativeLayout>
这个例子的效果图如下:
这样是可以将几个图片布在一张大的图片上面的..
PS:上面的布局例子并非是地震widget的布局..
上面主要讲的是wdiget布局和数据获取
下来我们来讲如何按时间来定时取数据..假设我们半个小时更新一次数据.
Code
1 <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
2
3 android:updatePeriodMillis="8640000000" android:minWidth="250px"
4
5
6 android:initialLayout="@layout/widget_main">
7
8 </appwidget-provider>
这是一个appwidget-provider 的 xml,其中android:updatePeriodMillis="8640000000" 这个属性是说当前widget更新的频率.
我们当然可以利用这个来设定时间来更新,但是这样有个不好的地方,google官方推荐的更新时间是1个小时以上,如果更新过快的话就会比较耗电,毕竟手机还是属于受限设备.
这里我们就用service来做,当widget启动的时候我们启动一个service,在service里我们启动一个线程来取数据,取完数据发送一个自定义的Intent给我们的widget,我们的widget就更新界面,同时service里的线程Thread.sleep(1800000);然后会继续取数据来更新我们的widget的...
需要注意的是,不要忘了在manifast里注册我们的widget和service.
代码如下:
Code
1 package com.gtrgtr.earthquake;
2
3
4 import java.io.InputStream;
5
6 import java.net.HttpURLConnection;
7
8 import java.net.URL;
9
10
11 import android.app.PendingIntent;
12
13 import android.app.Service;
14
15 import android.appwidget.AppWidgetManager;
16
17 import android.appwidget.AppWidgetProvider;
18
19 import android.content.ComponentName;
20
21 import android.content.Context;
22
23 import android.content.Intent;
24
25 import android.graphics.Bitmap;
26
27 import android.graphics.BitmapFactory;
28
29 import android.os.Bundle;
30
31 import android.os.IBinder;
32
33 import android.widget.RemoteViews;
34
35
36 public class MainWidget extends AppWidgetProvider {
37
38 //更新widget的Intent
39
40 public static final String CLOCKUPDATEACTION = "com.gtrgtr.UPDATETIME";
41
42 //自定义网络异常Intent
43
44 public static final String NETERROR = "com.gtrgtr.NETERRORS";
45
46 //重新加载widget
47
48 public static final String RELOAD = "com.gtrgtr.RELOAD";
49
50 private static boolean flag; //标志位
51
52 private Bitmap bmImg = null;
53
54 private RemoteViews views = null;
55
56 @Override
57
58 public void onEnabled(Context context) {
59
60 super.onEnabled(context);
61
62 }
63
64
65 @Override
66
67 public void onReceive(Context context, Intent intent) {
68
69 super.onReceive(context, intent);
70
71 AppWidgetManager am = AppWidgetManager.getInstance(context);
72
73 views = new RemoteViews(context.getPackageName(), R.layout.main);
74
75 String action = intent.getAction();
76
77 Bundle extras = intent.getExtras();
78
79 if (action.equals(AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
80
81 } else if (action.equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)) {
82
83 //在这里我们启动service
84
85 context.startService(new Intent(context, WorldDaylightService.class));
86
87 flag = true; //启动线程
88
89 } else if (action.equals(CLOCKUPDATEACTION)) {
90
91 //更新我们的widget
92
93 bmImg = extras.getParcelable("img");
94
95
96 } else if (action.equals(NETERROR)) {// Net error
97
98 //网络异常处理
99
100 flag = false;
101
102 context.stopService(new Intent(context, EarthQuakeService.class));
103
104 Intent intentx = new Intent(RELOAD);
105
106 PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentx, 0);
107
108 views.setOnClickPendingIntent(R.id.xa1, pendingIntent);
109
110
111 } else if (action.equals(RELOAD)) {
112
113 //重新加载
114
115 context.startService(new Intent(context, EarthQuakeService.class));
116
117 flag = true;
118
119 }
120
121 if (action.equals(AppWidgetManager.ACTION_APPWIDGET_DELETED) || action.equals(AppWidgetManager.ACTION_APPWIDGET_DISABLED)) {
122
123 //widget销毁处理
124
125 flag = false;
126
127 context.stopService(new Intent(context, EarthQuakeService.class));
128
129
130 } else {
131
132 views.setImageViewBitmap(R.id.widgetImageView, bmImg);
133
134 Intent intentx = new Intent(context, ToaskService.class);
135
136 PendingIntent pendingIntentx = PendingIntent.getService(context, 0, intentx, 0);
137
138 views.setOnClickPendingIntent(R.id.xa1, pendingIntentx);
139
140 ComponentName thisWidget = new ComponentName(context, MainWidget.class);
141
142 am.updateAppWidget(thisWidget, views);
143
144 }
145
146 }
147
148
149 public static class EarthQuakeService extends Service implements Runnable {
150
151 @Override
152
153 public void onStart(Intent intent, int startId) {
154
155 super.onStart(intent, startId);
156
157 new Thread(this).start();// startThread
158
159 }
160
161
162 @Override
163
164 public IBinder onBind(Intent intent) {
165
166 return null;
167
168 }
169
170
171 public void run() {
172
173 while (MainWidget.flag) {
174
175 Bitmap bmImg = null;
176
177 URL myFileUrl = null;
178
179 try {
180
181 //处理我们的数据
182
183 Intent intent = new Intent(CLOCKUPDATEACTION);
184
185 Bundle extras = new Bundle();
186
187 extras.putParcelable("img", bmImg);
188
189 intent.putExtras(extras);
190
191 //发送自定义Intent消息,通知界面更新数据
192
193 sendBroadcast(intent);
194
195 } catch (Exception e) {
196
197 //出现网络或其它异常处理的地方
198
199 Intent intent = new Intent(NETERROR);
200
201 sendBroadcast(intent);
202
203 }
204
205 try {
206
207 //我们睡半个小时再去取一次数据看看
208
209 Thread.sleep(1800000);
210
211 } catch (Exception e) {
212
213 }
214
215 }
216
217 }
218
219 }
220
221 }
除此之外,我们还能做个settings.方便用户来作设置之类的操作,这些都可以由大家来随便发挥了,总的来说,这还算是一不算难的widget了,我觉得唯一有些繁琐的地方就是XML的解析了,其它基本上没什么难的地方,毕竟这只是一个小小的 widget.
PS:这个仅仅是我的思路,具体的实现由于是在是没有时间,也就无法放出源代码了,是在是抱歉.以后如果有机会的话我会完全写出来并放出源代码的..