基于Android平台的天气预报短信服务系统课程设计_第1页
基于Android平台的天气预报短信服务系统课程设计_第2页
基于Android平台的天气预报短信服务系统课程设计_第3页
基于Android平台的天气预报短信服务系统课程设计_第4页
基于Android平台的天气预报短信服务系统课程设计_第5页
已阅读5页,还剩76页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

79/81目录1. 需求分析 11.1功能需求 11.2界面需求 11.3内部功能 12. 程序设计 22.1用户界面设计 22.2数据库设计 22.2.1配置信息 22.2.2SMS短信服务信息 32.3程序模块设计 33. 程序开发 43.1文件结构与用途 43.2数据库适配器 53.3短信监听器 83.4后台服务 103.4.1短信发送模块 113.4.2数据库猎取模块 133.5用户界面 173.5.1WeatherActivity 183.5.2HistoryActivity 193.5.3SetupActivity 243.5.4GoogleMapActivity 254.总结 345.参考文献 35天气预报短信服务系统需求分析1.1功能需求天气预报短信服务系统中,有一个显示天气情况的用户界面,能够通过图片和文字显示当前和以后几天的天气状况,包括温度、湿度、风向和雨雪情况等。这些天气数据是通过后台服务猎取的,那个后台服务能够按照一定时刻间隔,从Yahoo上猎取天气预报信息,并将天气信息保存在后台服务中。系统还需要提供基于SMS短信的天气数据服务,其他手机用户能够向本示例所在的手机上发送SMS短信,并在短信中包含用户指定的关键字,则能够将保存在后台服务中的天气情况,再通过SMS短信回复给用户。最后,每个被发送的SMS短信都要被记录下来,用户能够扫瞄或删除这些回复信息。本系统还要显示地图,在地图上显示某地点的天气信息。1.2界面需求本示例包含三个要紧的用户界面:(1)显示天气预报的用户界面;(2)显示已发送SMS短信的用户界面;(3)扫瞄和设置配置信息的用户界面;(4)Google地图,在地图上覆盖天气信息。1.3内部功能隐藏在用户界面后面的内部功能,是用户界面能够正确实现的基础,如下所述:(1)显示天气预报的用户界面;(2)猎取Yahoo的天气数据;(3)显示SMS短信的用户界面;(4)依照关键字监视SMS短信;(5)发送包含天气信息的SMS短信;(6)将发送的SMS短信写入数据库;(7)扫瞄和设置配置信息的用户界面;(8)将用户设置的配置信息保存到数据库;(9)启动时读取数据库中的配置信息;(10)恢复缺省设置;(11)显示Google地图且覆盖天气信息的用户界面,写入猎取的谷歌密钥。

程序设计2.1用户界面设计详细分析应用程序中四个要紧用户界面包含的显示内容,如下所述:(1)在“显示天气预报的用户界面”中,依照Yahoo能够提供的数据,在界面上能够显示当前的天气状况,包括都市名称、温度、雨雪情况和猎取数据时刻等信息;还能够显示以后一天的天气状况,仅包括温度和雨雪情况;(2)在“显示已发送SMS短信的用户界面”中,应显示每个回复短信的时刻、目标手机号码、都市名称、当天的天气状况和以后一天的天气状况;(3)在“扫瞄和设置配置信息的用户界面”中,应显示猎取天气预报的目标都市名称、猎取数据的频率和短信的关键字,并同意用户设置是否提供短信服务以及是否记录回复的短信信息;(4)在“显示谷歌地图及在地图上覆盖天气信息界面”中,应显示Google地图,当用户点击地图上某都市时,会显示某都市信息及天气情况。2.2数据库设计本系统要紧存储两种数据,详述如下:(1)配置信息:因为配置信息的数据量专门小,从Android支持的存储方式上分析,能够保存在SharePreference、文件或SQLite数据库中;(2)SMS短信服务信息:SMS短信服务信息是一个随着时刻推移而不断增加的数据,属于文本信息,且有固定的格式,因此适合使用SQLite数据库进行存储。综合分析这两种需要存储的数据,选择SQLite数据库作为存储数据的方法2.2.1配置信息配置信息中要紧保存天气信息查询的都市名称,访问Yahoo更新天气信息的频率,请求天气信息SMS短信的关键字,且是否提供短信服务和是否记录短信服务内容,其数据库表如下:表2_1配置信息的数据库属性数据类型讲明_idinteger自动增加的主键city_nametext进行天气信息查询的都市名refresh_speedtext进行天气信息查询的频率,单位为秒/次sms_servicetext是否提供短信服务,即接收到请求短信后是否回复包含天气信息的短信sms_infotext是否记录发出的SMS短信的信息key_wordtext短信服务的关键字,用以确定哪条是请求天气服务的短信2.2.2SMS短信服务信息SMS短信服务信息要紧保存请求服务短信的发送者、短信内容、接收时刻和回复信息的内容,其数据库表如下:表2_2SMS短信服务信息的数据库属性数据类型讲明_idinteger自动增加的主键sms_sendertext请求服务短信的发送者sms_bodytext请求服务短信的内容信息sms_receive_timetext接收到请求服务短信的时刻return_resulttext回复短信的内容2.3程序模块设计从功能需求上分析,能够将整个应用程序划分为4个模块,分不是用户界面、后台服务、数据库适配器和短信监听器。1.由模块结构图中可知,后台服务是整个应用程序的核心,要紧包含两个子模块,一个是“数据猎取模块”,负责周期性的从Yahoo猎取天气信息;另一个是“短信服务模块”,负责处理接收到的服务请求短信,并发送包含天气信息的短信2.后台服务由用户界面通过Intent启动,启动后的后台服务能够在用户界面关闭后仍然保持运行状态,直到用户通过用户界面发送Intent停止服务,或系统因资源不足而强行关闭服务3.用户界面从后台服务猎取天气信息,而没有直接通过网络访问Google的天气数据(1)一方面是因为后台服务使用了工作线程,通过后台服务猎取天气数据能够幸免因网络通信不畅造成界面失去响应(2)另一方面,在用户关闭界面后,后台服务仍然需要更新天气信息,以保证短信服务数据的准确性。用户界面还会调用数据库适配器,向SQLite数据库中写入、读取配置信息,或对SMS短信服务信息进行操作4.短信监听器是一个BroadcastReceiver,监视所有接收到的短信(1)假如短信中包含用户自定义的关键字,短信监听器则会认为这条短信是天气服务请求短信,将短信的相关信息写入后台服务的短信服务队列(2)假如用户在配置信息中选择无需提供短信服务,短信监听器仍然接着监听所有短信,只是后台服务不再同意将服务请求短信写入服务队列5.数据库适配器封装了所有对SQLite数据库操作的方法,用户界面和后台服务会调用它实现数据库操作。程序开发3.1文件结构与用途在程序开发时期,首先确定“天气预报短信服务系统”的工程名称为MyWeather,包名称为edu.hrbeu.WeatherDemo,据程序模块设计的内容,建立WeatherDemo。为了使源代码文件的结构更加清晰,WeatherDemo设置了多个命名空间,分不用来保存用户界面、数据库、后台服务、SMS短信和天气数据的源代码文件,命名空间的名称以及讲明参考表3_1。表3_1WeatherDemo的命名空间命名空间讲明edu.hrbeu.WeatherDemo存放与用户界面相关的源代码文件edu.hrbeu.WeatherDemo.DB存放与SQLite数据库相关的源代码文件edu.hrbeu.WeatherDemo.Service存放与后台服务相关的源代码文件edu.hrbeu.WeatherDemo.SMS存放与SMS短信相关的源代码文件WeatherDemo示例将不同用途的源代码文件放置在不同的命名空间中,源代码文件的名称和用途能够参考表3_2。表3_2WeatherDemo的文件用途讲明包名称文件名讲明.WeatherDemoHistoryActivity.java“历史数据”页的ActivitySetupActivity.java“系统设置”页的ActivityWeatherActivity.java“天气预报”页的ActivityGoogleMapActivity.java“谷歌地图”页的ActivityTextOverlay.java地图覆盖天气信息的类WeatherDemo.java程序启动缺省的Activity.WeatherDemo.DBConfig.java保存配置信息的类DBAdapter.java数据库适配器City.java覆盖天气的都市信息的类.WeatherDemo.ServiceSmsReceiver.java短信监听器WeatherAdapter.java数据猎取模块WeatherService.java后台服务.WeatherDemo.SMSSimpleSms.java简化的SMS短信类SmsAdapter.java短信发送模块.WeatherDemo.WeatherForecast.java以后信息的类Weather.java当前天气信息的类Android的资源文件保存在/res的子目录中:(1)/res/drawable目录中保存的是图像文件(2)/res/layout目录中保存的是布局文件(3)/res/values目录中保存的是用来定义字符串和颜色的文件(4)/res/xml目录保存的是XML格式的数据文件所有在程序开发时期能够被调用的资源都保存在这些目录中,具体每个资源文件的用途能够参考表3_3。表3_3资源文件名称与用途资源目录文件讲明drawableicon.png图标文件sunny.png调试用的天气图片tab_history.pngTabHost中“历史数据”页的图片tab_map.pngTabHost中“谷歌地图”页的图片tab_setup.pngTabHost中“系统设置”页的图片tab_weather.pngTabHost中“天气预报”页的图片layoutdata_row.xml“历史数据”页ListActivity的每行数据的布局tab_history.xmlTabHost中“历史数据”页的布局tab_map.xmlTabHost中“谷歌地图”页的布局tab_setup.xmlTabHost中“系统设置”页的布局tab_weather.xmlTabHost中“天气预报”页的布局valuescolor.xml保存颜色的XML文件string.xml保存字符串的XML文件xmlapi.xml从Google下载的天气数据文件。在程序运行时没有实际作用,但在开发过程中能够让读者了解数据格式3.2数据库适配器数据库适配器是最底层的模块,要紧用于封装用户界面和后台服务对SQLite数据库的操作,数据库适配器的核心代码要紧在DBAdapter.java文件中,用户保存配置信息的类文件Config.java。Config.java文件的全部代码如下packageedu.hrbeu.WeatherDemo.DB;publicclassConfig{ publicstaticStringCityName; publicstaticStringRefreshSpeed; publicstaticStringProvideSmsService; publicstaticStringSaveSmsInfo; publicstaticStringKeyWord; publicstaticvoidLoadDefaultConfig(){ CityName="chaohu"; RefreshSpeed="20"; ProvideSmsService="true"; SaveSmsInfo="true"; KeyWord="HF";}从代码中不难看出,公有静态属性CityName、RefreshSpeed、ProvideSmsService、SaveSmsInfo和KeyWord,完全对应数据库中保存配置信息表的属性。在程序启动后,保存在数据库中的都市名称、更新频率、是否提供短信服务、是否保存短信信息和关键字等内容,将被写入那个Config类中,供其他模块在做逻辑推断LoadDefaultConfig()函数保存了程序内置的配置参数,此函数会在两个情况下被调用(1)用户主动选择“恢复缺省设置”(2)首次启动程序时,用来初始化保存配置参数的数据库DBAdapter类与以往介绍过的数据库适配器类相似,都具有继承SQLiteOpenHelper的关心类DBOpenHelper。DBOpenHelper在建立数据库时,同时建立两个数据库表,并对保存配置信息的表进行了初始化,初始化的相关代码在如下: privatestaticfinalStringDB_NAME="weather_app.db"; privatestaticfinalStringDB_TABLE_CONFIG="setup_config"; privatestaticfinalStringDB_CONFIG_ID="1"; privatestaticfinalintDB_VERSION=1; publicstaticfinalStringKEY_ID="_id"; publicstaticfinalStringKEY_CITY_NAME="city_name"; publicstaticfinalStringKEY_REFRESH_SPEED="refresh_speed"; publicstaticfinalStringKEY_SMS_SERVICE="sms_service"; publicstaticfinalStringKEY_SMS_INFO="sms_info"; publicstaticfinalStringKEY_KEY_WORD="key_word"; privatestaticfinalStringDB_TABLE_SMS="sms_data"; publicstaticfinalStringKEY_SENDER="sms_sender"; publicstaticfinalStringKEY_BODY="sms_body"; publicstaticfinalStringKEY_RECEIVE_TIME="sms_receive_time"; publicstaticfinalStringKEY_RETURN_RESULT="return_result";/**静态Helper类,用于建立、更新和打开数据库*/ privatestaticclassDBOpenHelperextendsSQLiteOpenHelper{ publicDBOpenHelper(Contextcontext,Stringname,CursorFactoryfactory,intversion){ super(context,name,factory,version); } privatestaticfinalStringDB_CREATE_CONFIG="createtable"+ DB_TABLE_CONFIG+"("+KEY_ID+"integerprimarykeyautoincrement,"+ KEY_CITY_NAME+"textnotnull,"+KEY_REFRESH_SPEED+"text,"+ KEY_SMS_SERVICE+"text,"+KEY_SMS_INFO+"text,"+ KEY_KEY_WORD+"text);"; privatestaticfinalStringDB_CREATE_SMS="createtable"+ DB_TABLE_SMS+"("+KEY_ID+"integerprimarykeyautoincrement,"+ KEY_SENDER+"textnotnull,"+KEY_BODY+"text,"+ KEY_RECEIVE_TIME+"text,"+KEY_RETURN_RESULT+"text);"; @Override publicvoidonCreate(SQLiteDatabase_db){ _db.execSQL(DB_CREATE_CONFIG); _db.execSQL(DB_CREATE_SMS); //初始化系统配置的数据表 Config.LoadDefaultConfig(); ContentValuesnewValues=newContentValues(); newValues.put(KEY_CITY_NAME,Config.CityName); newValues.put(KEY_REFRESH_SPEED,Config.RefreshSpeed); newValues.put(KEY_SMS_SERVICE,Config.ProvideSmsService); newValues.put(KEY_SMS_INFO,Config.SaveSmsInfo); newValues.put(KEY_KEY_WORD,Config.KeyWord); _db.insert(DB_TABLE_CONFIG,null,newValues); } @Override publicvoidonUpgrade(SQLiteDatabase_db,int_oldVersion,int_newVersion){ _db.execSQL("DROPTABLEIFEXISTS"+DB_TABLE_CONFIG); _db.execSQL("DROPTABLEIFEXISTS"+DB_CREATE_SMS); onCreate(_db); } }在DBAdapter类中,用户界面会调用SaveConfig()和LoadConfig(),从SQLite数据库中保存和读取配置信息。保存配置信息时,SaveConfig()函数会将Config类中的公有静态属性写入数据库;反之,LoadConfig()会将数据库中的配置信息写入Config类中的公有静态属性SaveConfig()和LoadConfig()的代码如下publicvoidSaveConfig(){ ContentValuesupdateValues=newContentValues(); updateValues.put(KEY_CITY_NAME,Config.CityName); updateValues.put(KEY_REFRESH_SPEED,Config.RefreshSpeed); updateValues.put(KEY_SMS_SERVICE,Config.ProvideSmsService); updateValues.put(KEY_SMS_INFO,Config.SaveSmsInfo); updateValues.put(KEY_KEY_WORD,Config.KeyWord); db.update(DB_TABLE_CONFIG,updateValues,KEY_ID+"="+DB_CONFIG_ID,null); Toast.makeText(context,"系统设置保存成功",Toast.LENGTH_SHORT).show(); }另一个会调用DBAdapter类的是后台服务,即WeatherService类。后台服务要紧调用SaveOneSms(SimpleSmssms)、DeleteAllSms()和GetAllSms()函数,分不用来保存SMS短信记录、删除所有SMS数据记录和猎取所有SMS数据记录。在GetAllSms()函数中,调用了一个私有函数ToSimpleSms(Cursorcursor),用来将从数据库猎取的数据转换为SimpleSms对象数组。SimpleSms类将在下面内容中进行介绍下面是SaveOneSms(SimpleSmssms)、DeleteAllSms()和GetAllSms()函数的代码:publicvoidSaveOneSms(SimpleSmssms){ ContentValuesnewValues=newContentValues(); newValues.put(KEY_SENDER,sms.Sender); newValues.put(KEY_BODY,sms.Body); newValues.put(KEY_RECEIVE_TIME,sms.ReceiveTime); newValues.put(KEY_RETURN_RESULT,sms.ReturnResult); db.insert(DB_TABLE_SMS,null,newValues); } publiclongDeleteAllSms(){ returndb.delete(DB_TABLE_SMS,null,null); } publicSimpleSms[]GetAllSms(){ Cursorresults=db.query(DB_TABLE_SMS,newString[]{KEY_ID,KEY_SENDER, KEY_BODY,KEY_RECEIVE_TIME,KEY_RETURN_RESULT}, null,null,null,null,null); returnToSimpleSms(results);} privateSimpleSms[]ToSimpleSms(Cursorcursor){ intresultCounts=cursor.getCount(); if(resultCounts==0||!cursor.moveToFirst()){ returnnull;} SimpleSms[]sms=newSimpleSms[resultCounts]; for(inti=0;i<resultCounts;i++){ sms[i]=newSimpleSms(); sms[i].Sender=cursor.getString(cursor.getColumnIndex(KEY_SENDER)); sms[i].Body=cursor.getString(cursor.getColumnIndex(KEY_BODY)); sms[i].ReceiveTime=cursor.getString(cursor.getColumnIndex(KEY_RECEIVE_TIME)); sms[i].ReturnResult=cursor.getString(cursor.getColumnIndex(KEY_RETURN_RESULT)); cursor.moveToNext(); } returnsms;}3.3短信监听器短信监听器本质上是BroadcastReceiver,用于监听Android系统所接收到的所有SMS短消息,能够在应用程序关闭后仍然接着运行,核心代码在SmsReceiver.java文件中。在介绍SmsReceiver类前,先讲明用来保存SMS短信内容和相关信息的SimpleSms类。android.telephony.gsm.SmsMessage是Android提供的短信类,但那个地点需要一个更精简、小巧的类,保存少量的信息,因此构造了SimpleSms类,仅用来保存短信的发送者、内容、接收时刻和返回结果。那个地点的“返回结果”指的是返回包含天气信息的短信内容SimpleSms.java文件完整代码如下:packageedu.hrbeu.WeatherDemo.SMS;importjava.text.SimpleDateFormat;publicclassSimpleSms{ publicStringSender; publicStringBody; publicStringReceiveTime; publicStringReturnResult; publicSimpleSms(){ } publicSimpleSms(Stringsender,Stringbody){ this.Sender=sender; this.Body=body; SimpleDateFormattempDate=newSimpleDateFormat("yyyy-MM-dd"+""+"hh:mm:ss"); this.ReceiveTime=tempDate.format(newjava.util.Date()); this.ReturnResult=""; }}上述代码的属性Sender、Body、ReceiveTime和ReturnResult,分不表示SMS短信的发送者、内容、接收时刻和返回结果。上述代码在SimpleSms类的构造函数中,直接将系统时刻以“年-月-日小时:分:秒”的格式保存在ReceiveTime属性中。SmsReceiver类继承BroadcastReceiver,重载了onReceive()函数。事实上系统消息的识不和系统关键字的识不并不复杂,我们只要能够接收到vider.Telephony.SMS_RECIVED类型的系统消息,则表明是Android系统接收到了短信;将短信的内容拆分后,推断消息内容是否是配置信息中定义的关键字,即可推断该短信是否为天气服务请求短信。SmsReceiver.java文件的核心代码publicclassSmsReceiverextendsBroadcastReceiver{ privatestaticfinalStringSMS_ACTION="vider.Telephony.SMS_RECEIVED"; @Override publicvoidonReceive(Contextcontext,Intentintent){ if(intent.getAction().equals(SMS_ACTION)){ Bundlebundle=intent.getExtras(); if(bundle!=null){ Object[]objs=(Object[])bundle.get("pdus"); SmsMessage[]messages=newSmsMessage[objs.length]; for(inti=0;i<objs.length;i++){ messages[i]=SmsMessage.createFromPdu((byte[])objs[i]); } StringsmsBody=messages[0].getDisplayMessageBody(); StringsmsSender=messages[0].getDisplayOriginatingAddress(); if(smsBody.trim().equals(Config.KeyWord) &&Config.ProvideSmsService.equals("true")){ SimpleSmssimpleSms=newSimpleSms(smsSender,smsBody); WeatherService.RequerSMSService(simpleSms); Toast.makeText(context,"接收到服务请求短信",Toast.LENGTH_SHORT) .show(); } } } }}第10行代码将带有pdus字符串特征的对象,通过Bundle.get()函数提取出来,在第12行代码使用SmsMessage.CreateFromPdu()函数构造SmsMessage对象,在第11行代码使用循环语句是因为接收到的短信可能不止一条,从第14行和第15行代码上看,那个地点只处理第1条短信,第17行代码构造SimpleSms对象,在代码第18行调用WeatherService类的RequerSMSService()函数,将SimpleSms对象添加到短信队列中在AndroidManifest.xml文件中注册短信监听器SmsReceiver,并声明能够接收短信的用户许可android.permission.RECEIVE_SMS假如注册的组件不在根命名空间中,则需要将子命名空间写在类的前面。例如下面在代码第1行中,因为SmsReceiver.java文件在edu.hrbeu.WeatherDemo.Service命名空间下,而不在根命名空间edu.hrbeu.WeatherDemo下,因此注册组件时需要在类名SmsReceiver前添加.Service<receiverandroid:name=".Service.SmsReceiver"> <intent-filter><actionandroid:name="vider.Telephony.SMS_RECEIVED"/> </intent-filter></receiver><uses-permissionandroid:name=”android.permission.RECEIVE_SMS”/>3.4后台服务后台服务是WeatherDemo示例的核心模块,在用户启动后持续在后台运行,直到用户手动停止服务。后台服务功能:一是发送包含天气信息的SMS短信(短信发送模块)二是周期性的猎取Yahoo的天气数据(数据猎取模块)3.4.1短信发送模块后台服务在单独的线程上运行,首先调用ProcessSmsList()函数,检查短信队列中是否有需要回复的短信,然后调用GetGoogleWeatherData()函数猎取天气数据,最后线程暂停1秒,以释放CPU资源,WeatherDemo示例后台服务的核心代码在WeatherService.java文件中下面是线程调用函数的部分代码如下所述:privatestaticArrayList<SimpleSms>smslist=newArrayList<SimpleSms>();privateRunnablebackgroudWork=newRunnable(){ @Override publicvoidrun(){ try{ while(!Terrupted()){ ProcessSmsList(); GetGoogleWeatherData(); Thread.sleep(1000); } } catch(InterruptedExceptione){ e.printStackTrace(); } } };ProcessSmsList()函数用来检查短信列表smsList,并依照Weather类中保存的天气数据,向请求者的发送回复短信,WeatherService.java文件的ProcessSmsList()函数代码如下:privatevoidProcessSmsList(){ if(smsList.size()==0){ return; } SmsManagersmsManager=SmsManager.getDefault(); PendingIntentmPi=PendingIntent .getBroadcast(this,0,newIntent(),0); while(smsList.size()>0){ SimpleSmssms=smsList.get(0); smsList.remove(0); smsManager.sendTextMessage(sms.Sender,null,Weather.GetSmsMsg(), mPi,null); sms.ReturnResult=Weather.GetSmsMsg(); SaveSmsData(sms); } }发送短信是使用SmsManager对象的sendTextMessage()方法,该方法一共需要5个参数:第1个参数是收件人地址,第2个参数是发件人地址,第3个参数是短信正文,第4个参数是发送服务,第5个参数是送达服务。sendTextMessage()方法的收件人地址和短信正文是不可为空的参数,而且一般GSM规范要求短信内容要操纵在70个汉字以内。代码第8行的Weather.GetSmsMsg(),用来获得供回复短信使用的天气信息,因为考虑到短信的字数限制,仅返回当天和以后一天的天气状况。Weather.java文件的代码如下:packageedu.hrbeu.WeatherDemo.Weather;importandroid.graphics.Bitmap;publicclassWeather{ publicstaticStringcity; publicstaticStringcode; publicstaticStringcountry; publicstaticStringtLowT; publicstaticStringtHighT; publicstaticStringtemp; publicstaticStringtDescription; publicstaticStringlatitude; publicstaticStringlongitude; publicstaticStringtime; publicstaticStringday_of_week; publicstaticStringcurrent_image_url; publicstaticBitmapcurrent_image; publicstaticForecast[]forecast=newForecast[2]; static{ for(inti=0;i<forecast.length;i++){ forecast[i]=newForecast(); } } publicstaticStringGetSmsMsg(){ Stringmsg=""; msg+=city+","; msg+=country+","+latitude+"."+longitude; msg+=","+day_of_week+","+tDescription+","+temp+"℃"; returnmsg; }}Forecast.java文件的代码如下:packageedu.hrbeu.WeatherDemo.Weather;importandroid.graphics.Bitmap;publicclassForecast{ publicStringday_of_week; publicStringlow; publicStringhigh; publicStringimage_url; publicBitmapimage; publicStringcondition;}3.4.2数据库猎取模块数据猎取模块:天气数据是从Yahoo提供的WebService中猎取的,数据的猎取地址是/forecastrss?p=CHXX0037&u=c,CHXX0037表示猎取广州的天气数据,读者能够替换CHXX0037,并将新的地址输入Web扫瞄器,在扫瞄器中能够直接看到XML格式的天气数据。在资源目录中的/res/xml/api.xml文件,确实是2012年12月16日api.xml文件的内容如下:<?xmlversion="1.0"encoding="UTF-8"standalone="yes"?> <rssversion="2.0"xmlns:yweather="/ns/rss/1.0"xmlns:geo="/2003/01/geo/wgs84_pos#"> <channel> <title>Yahoo!Weather-Guangzhou,CH</title><link>/dailynews/rss/weather/Guangzhou__CH/*/forecast/CHXX0037_c.html</link><description>Yahoo!WeatherforGuangzhou,CH</description><language>en-us</language><lastBuildDate>Sun,16Dec201210:00amCST</lastBuildDate><ttl>60</ttl><yweather:locationcity="Guangzhou"region=""country="CH"/><yweather:unitstemperature="C"distance="km"pressure="mb"speed="km/h"/><yweather:windchill="24"direction="0"speed="0"/><yweather:atmospherehumidity="83"visibility="2.49"pressure="1015.92"rising="0"/><yweather:astronomysunrise="7:01am"sunset="5:43pm"/><image><title>Yahoo!Weather</title><width>142</width><height>18</height><link></link><url>/a/i/brand/purplelogo//uh/us/news-wea.gif</url></image><item><title>ConditionsforGuangzhou,CHat10:00amCST</title><geo:lat>23.12</geo:lat><geo:long>113.3</geo:long><link>/dailynews/rss/weather/Guangzhou__CH/*/forecast/CHXX0037_c.html</link><pubDate>Sun,16Dec201210:00amCST</pubDate><yweather:conditiontext="Fog"code="20"temp="24"date="Sun,16Dec201210:00amCST"/><description><![CDATA[<imgsrc="/a/i/us/we/52/20.gif"/><br/><b>CurrentConditions:</b><br/>Fog,24C<BR/><BR/><b>Forecast:</b><BR/>Sun-PartlyCloudy.High:26Low:16<br/>Mon-PartlyCloudy.High:24Low:16<br/><br/><ahref="/dailynews/rss/weather/Guangzhou__CH/*/forecast/CHXX0037_c.html">FullForecastatYahoo!Weather</a><BR/><BR/>(providedby<ahref="">TheWeatherChannel</a>)<br/>]]></description><yweather:forecastday="Sun"date="16Dec2012"low="16"high="26"text="PartlyCloudy"code="30"/><yweather:forecastday="Mon"date="17Dec2012"low="16"high="24"text="PartlyCloudy"code="30"/><guidisPermaLink="false">CHXX0037_2012_12_17_7_00_CST</guid></item></channel></rss><!--SunDec1603:10:19PST2012-->WeatherAdapter类实现了利用URL猎取位图的私有函数GetURLBitmap(),以及用来下载和解析XML数据的公有函数GetWeatherData()。后台服务在调用GetWeatherData()函数解析Yahoo提供的天气数据时,会不断调用GetURLBitmap()函数,将XML数据中的天气图标依照图标地址下载到本地保存。GetURLBitmap()函数的代码如下:privatestaticBitmapGetURLBitmap(StringurlString){ URLurl=null; Bitmapbitmap=null; try{ url=newURL("/a/i/us/we/52/"+urlString +".gif"); } catch(MalformedURLExceptione){ e.printStackTrace(); } try{ HttpURLConnectionconn=(HttpURLConnection)url.openConnection(); conn.connect(); InputStreamis=conn.getInputStream(); bitmap=BitmapFactory.decodeStream(is); is.close(); } catch(IOExceptione){ e.printStackTrace(); } returnbitmap; }}getweather()函数首先依照指定的URL地址,从网络猎取字节流数据,然后调用轻量级XML解析器XmlPullParser对天气数据进行解析,并将解析结果保存在Weather类的公有静态属性中getweather()函数的代码如下:publicstaticvoidgetWeather()throwsMalformedURLException, XmlPullParserException,IOException{ Stringvalue=City.getCode(Config.CityName); StringqueryString="/forecastrss?w=" +value+"&u=c"; System.out.println(queryString); System.out.println(Config.CityName) XmlPullParserparser=Xml.newPullParser(); parser.setInput(newURL(queryString).openConnection().getInputStream(), "UTF-8"); intcode=parser.getEventType(); StringpreString=null; intposition=0; while(code!=XmlPullParser.END_DOCUMENT){ switch(code){ caseXmlPullParser.START_TAG: preString=parser.getName(); if(preString.equals("location")){ Weather.city=parser.getAttributeValue(0); Weather.country=parser.getAttributeValue(2); } elseif(preString.equals("condition")){ Weather.tDescription=parser.getAttributeValue(0); Weather.current_image_url=parser.getAttributeValue(1); Weather.temp=parser.getAttributeValue(2); Weather.day_of_week=parser.getAttributeValue(3); Weather.current_image=GetURLBitmap(Weather.current_image_url); } elseif(preString.equals("forecast")){ Weather.forecast[position].low=parser .getAttributeValue(2); Weather.forecast[position].high=parser .getAttributeValue(3); Weather.forecast[position].day_of_week=parser .getAttributeValue(0); Weather.forecast[position].condition=parser .getAttributeValue(4); Weather.forecast[position].image_url=parser .getAttributeValue(5); Weather.forecast[position].image=GetURLBitmap(Weather.forecast[position].image_url); position++; } break; caseXmlPullParser.END_TAG: preString=null; break; caseXmlPullParser.TEXT: if(preString==null) break; if(preString.equals("lat")){ Weather.latitude=parser.getText(); } elseif(preString.equals("long")){ Weather.longitude=parser.getText(); } elseif(preString.equals("pubDate")) Weather.time=parser.getText(); break; caseXmlPullParser.START_DOCUMENT: break; default: break; } code=parser.next(); } }最后,在AndroidManifest.xml文件中注册WeatherService,并声明连接互联网和发送SMS短信的两个用户许可。<serviceandroid:name=”.Service.WeatherService”/><uses-permissionandroid:name="android.permission.INTERNET"/> <uses-permissionandroid:name="android.permission.RECEIVE_SMS"/>3.5用户界面在用户界面设计上,采纳能够在多个分页上快速切换的Tab标签页,WeatherDemo示例的Tab标签页将每个标签页与一个Activity关联在一起,如此做的好处确实是能够将不同标签页的代码放在不同的文件中,而且每个标签页都能够有独立的选项菜单。WeatherDemo类是继承TabActivity的Tab标签页,共设置3个标签页(1)TAB1标签页的标题为“天气预报”,关联的Activity为WeatherActivity(2)TAB2标签页的标题为“历史数据”,关联Activity为HistoryActivity(3)TAB3标签页的标题为“系统设置”,关联Activity为SetupActivity(4)TAB4标签页的标题为“地图信息”,关联Activity为GoogleMapActivityWeatherDemo.java文件的完整代码如下:packageedu.hrbeu.WeatherDemo;importandroid.app.TabActivity;importandroid.content.Intent;importandroid.os.Bundle;importandroid.widget.TabHost;publicclassWeatherDemoextendsTabActivity{ /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); TabHosttabHost=getTabHost(); tabHost.addTab(tabHost .newTabSpec("TAB1") .setIndicator("天气预报", getResources().getDrawable(R.drawable.tab_weather)) .setContent(newIntent(this,WeatherActivity.class))); tabHost.addTab(tabHost .newTabSpec("TAB2") .setIndicator("历史数据", getResources().getDrawable(R.drawable.tab_history)) .setContent(newIntent(this,HistoryActivity.class))); tabHost.addTab(tabHost .newTabSpec("TAB3") .setIndicator("系统设置", getResources().getDrawable(R.drawable.tab_setup)) .setContent(newIntent(this,SetupActivity.class))); tabHost.addTab(tabHost .newTabSpec("TAB4") .setIndicator("地图信息", getResources().getDrawable(R.drawable.tab_map)) .setContent(newIntent(this,GoogleMapActivity.class))); }}WeatherDemo.java中的代码只是用户界面的框架,设置了Tab标签页的图标、标题和所关联的Activity,标签页中的具体显示内容还要依靠于每个Activity所设置的界面布局。3.5.1WeatherActivityWeatherActivity在启动时并不能够显示最新的天气信息,用户需要通过选项菜单的“启动服务”开启后台服务,然后点击“刷新”猎取最新的天气状况,选项菜单还提供“停止服务”和“退出”选项。WeatherActivity使用的布局文件是tab_weather.xml,这是个较为繁琐的界面布局,多次的使用了垂直和水平的线性布局。WeatherActivity的界面布局和代码并不难以理解,因此那个地点不再给出WeatherActivity.java和tab_weather.xml具体代码。WeatherActivity用户界面图(启动服务后)如图3.5.1所示:图3.5.1WeatherActivity用户界面3.5.2HistoryActivityHistoryActivity:要紧用来显示SQLite数据库中的短信服务信息,显示的内容包括发送者的手机号码、时刻和回复短信内容。为了能够以列表的形式显示多行数据,并定制每行数据的布局。HistoryActivity用户界面图如图3.5.2所示:图3.5.2HistoryActivity用户界面那个地点使用了ListActivity,ListActivity能够不通过setContentView()设置布局,也不必重载onCreate()函数,而直接将显示列表加载到ListActivity,增加了使用的便利性。在WeatherDemo示例中,仍然使用setContentView()设置布局,如此做的好处是能够在界面中设置更为复杂的显示元素,例如在列表上方增加了提示信息“SQLite数据库中的短信服务信息”。下方的代码是HistoryActivity.java文件的onCreate()函数中的设置布局和加载适配器的关键代码:setContentView(R.layout.tab_history);setListAdapter(dataAdapter);tab_history.xml是HistoryActivity的布局文件,下面先分析一下tab_history.xml的内容tab_history.xml文件的完整代码如下:<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android" android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"android:background="@drawable/black"> <TextViewandroid:layout_width="wrap_content" android:layout_height="wrap_content"android:text="SQLite数据库中的短信服务信息:"> </TextView> <ListViewandroid:id="@android:id/list"android:layout_width="fill_parent" android:layout_height="wrap_content"android:layout_marginTop="2dip"> </ListView></LinearLayout>tab_history.xml中ListView控件,并使用系统的ID值“@android:id/list”,ListView的数据列配器是通过setListAdapter(dataAdapter)设置的。ListView使用的是自定义布局,布局保存在data_row.xml文件中,data_row.xml的完整代码如下:<LinearLayoutxmlns:android="/apk/res/android" android:orientation="horizontal"android:layout_width="fill_parent" android:layout_height="fill_parent"android:background="@drawable/white" android:layout_marginTop="2dip"> <LinearLayoutandroid:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent"> <TextViewandroid:id="@+id/data_row_01" android:layout_gravity="center_vertical"android:layout_width="fill_parent" android:layout_height="wrap_content"android:textSize="12dip" android:textColor="@drawable/black"/> <TextViewandroid:id="@+id/data_row_02" android:layout_gravity="center_vertical"android:layout_width="fill_parent" android:layout_height="wrap_content"android:textSize="12dip" android:textColor="@drawable/black"android:layout_marginTop="3dip"/> </LinearLayout></LinearLayout>Android提供的数据适配器仅同意保存字符串数组或列表对象,假如希望使用自定义布局,则需要实现自定义的数据适配器,并继承Android提供的BaseAdapter(Android.widget.BaseAdapter)对象。自定义的数据适配器在SmsAdapter.java文件中,其完整代码如下:packageedu.hrbeu.WeatherDemo.SMS;importandroid.content.Context;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.BaseAdapter;importandroid.widget.TextView;importedu.hrbeu.WeatherDemo.DB.DBAdapter;importedu.hrbeu.WeatherDemo.R;publicclassSmsAdapterextendsBaseAdapter{ privateLayoutInflatermInflater; privatestaticDBAdapterdbAdapter; privatestaticSimpleSms[]smsList; publicSmsAdapter(Contextcontext) {

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论