版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
摘要近年来,国民经济的持续、快速发展,人民生活水平日益提高,广大人民群众对生活质量的追求也越来越高。伴随而来的是近几年智能产品在中国的井喷式增长,智能产品已经开始慢慢渗透到每家每户。智能家居产品最初的发展主要以灯光遥控控制、电器远程控制和电动窗帘控制为主。随着行业的发展,智能控制的功能越来越多,控制的对象不断扩展,控制的联动场景要求更高,其不断延伸到家庭安防报警、背景音乐、可视对讲、门禁指纹控制等领域,可以说智能家居几乎可以涵盖所有传统的弱电行业。而现在,智能家居已经在往智能家电方向发展,例如扫地机器人、智能音箱、智能电饭煲等,拆箱即用,可以作为组成智能家居的一部分,这大大降低了购买成本和安装成本,使得普及率大大提高。目前,在开放二胎的政策下,城市婴儿出生率仍较低,城市婴儿得到重视。生活条件的上升,使得传统的婴儿床不再能满足年轻父母的需求。而现有的婴儿床,少有智能功能,婴儿床辅助用品有智能产品,但与婴儿床相互独立。于是,可以基于以上因素,设计一款带有监控系统的智能婴儿床。本文阐述的智能婴儿床手机监控系统采用的C/S模式设计,客户端基于安卓系统,数据库使用的是Mysql,硬件采用了树莓派以及摄像头模组和其他传感器。论文以电子信息技术对设计该系统进行系统分析,详细阐述了监控系统的需求分析,功能分析以及系统设计,给出了实现思路和实现方式,并且实现过程遵循良好的设计模式和工程要求,在大程度地降低系统的复杂性,提高系统的鲁棒性,为以后开展的设计工作,奠定良好的基础。图5副;表4个;参x篇;关键词:监控;安卓;智能家居;
Abstract Inrecentyears,withthesustainedandrapiddevelopmentofthenationaleconomy,thelivingstandardofthepeopleisimprovingdaybyday,andthepeople'spursuitforthequalityoflifeisalsogettinghigherandhigher.AccompaniedbytheexplosivegrowthofsmartproductsinChinainrecentyears,smartproductshavegraduallypenetratedintoeveryhousehold.Intelligenthouseholdproductsinitialdevelopmentmainlywithlamplightremotecontrol,electricremotecontrolandelectriccurtaincontrolisgivenpriorityto.Withthedevelopmentoftheindustry,thefunctionoftheintelligentcontrolisbecomingmoreandmoreexpandingcontrolobject,thelinkageofthecontrolscenarioismoredemanding,thecontinuouslyextendedtofamilysecurityalarm,backgroundmusic,videointercom,fingerprintcontroletc,cansaysmarthomecancoveralmostallthetraditionalweakcurrentindustry.Andnow,smarthomehasbeeninthedirectionofsmarthomeappliances,suchassweepingrobot,smartspeaker,smartricecooker,etc.,outofthebox,canbeusedaspartofthesmarthome,whichgreatlyreducesthecostofpurchaseandinstallationcosts,makingthepenetrationrategreatlyimproved.Atpresent,underthepolicyoftwo-childpolicy,thebirthrateofurbanbabiesisstilllow,andurbanbabiesarevalued.Aslivingconditionshaverisen,thetraditionalcribnolongermeetstheneedsofyoungparents.Andexistingcrib,littleintelligencefunction,cribauxiliarythingshasintelligenceproduct,butwithcribmutualindependence.Therefore,basedontheabovefactors,asmartcribwithmonitoringsystemcanbedesigned.TheC/Smodedesignisadoptedforthemonitoringsystemofthesmartcribphonedescribedinthispaper.Theclientisbasedontheandroidsystem,thedatabaseisMysql,andthehardwareisraspberrypie,cameramoduleandothersensors.Paperwithelectronicinformationtechnologytodesignthesystemtocarryonthesystemanalysis,monitoringandcontrolsystemwereintroducedindetailintherequirementanalysis,functionanalysisandsystemdesign,implementationapproachandimplementationapproachisgiven,andfollowthegooddesignpatterns,andprojectimplementationprocessrequirements,inlargeparttoreducethecomplexityofthesystem,improvetherobustnessofthesystem,tocarryoutdesignworklater,layagoodfoundation.
目录摘要 1Abstract 21 绪论 51.1 设计提出的背景、目的及研究意义 51.2 整体系统架构分析 51.2.1C/S架构 51.2.2HTTP 51.3 系统开发相关技术概述 61.3.1Java编程语言 61.3.2Android平台 61.3.3数据库 71.3.4Spring、SpringMVC框架结构及原理 71.3.5树莓派 81.3.6Nginx 81.3.7Rtmp协议 82 系统需求分析 92.1系统的功能需求分析概述 92.2系统功能分析 93 系统设计 103.1系统数据库设计 103.1.1用户信息表结构设计 103.1.2婴儿信息表结构设计 103.1.3用户-婴儿关系表结构设计 103.1.4用户-硬件关系表结构设计 113.2移动端系统的设计 113.2.1注册模块设计 113.2.2通信模块设计 123.2.3登录模块设计 153.2.4视频模块设计 163.2.5任务提醒模块设计 203.3服务端系统的设计 253.3.1服务端三层架构 253.3.2SSM框架 263.3.3注册模块设计 263.3.4登录模块设计 273.4硬件采集系统的设计 283.4.1树莓派与摄像头 283.4.2Nginx-rtmp-module流媒体服务器 283.4.3使用ffmpeg推流 29结论 31参考文献 32致谢 33
绪论设计提出的背景、目的及研究意义近年来,国民经济的持续、快速发展,人民生活水平日益提高,智能产品在中国井喷式,渗透进生活的方方面面。生活条件的上升,对下一代的重视,使得传统的婴儿床不再能满足年轻父母的需求。而现有的婴儿床,少有智能功能,婴儿床辅助用品有智能产品,但与婴儿床相互独立。于是,可以基于以上因素,设计一款智能婴儿床。智能婴儿床,其中一个核心功能是在手机端实时监控婴儿的息。所以本文以电子信息技术对设计基于智能婴儿床的监控系统进行系统分析,通过构建合理的系统架构模型,以及给出技术选型参考,旨在在大程度地降低系统的复杂性,辅助日后开展的设计工作。整体系统架构分析1.2.1C/S架构C/S(Client/Server)即客户机/服务器模式,分为客户机和服务器两层:第一层是在客户机系统上结合了表示与业务逻辑,第二层是通过网络结合了数据库服务器。简单的说就是第一层是用户表示层,第二层是数据库层。客户端和服务器直接相连,这两个组成部分都承担着重要的角色。C/S架构有着以下的优点:一、应用服务器运行数据负荷较轻。最简单的C/S体系结构的数据库应用由两部分组成,即客户应用程序和数据库服务器程序。二者可分别称为前台程序与后台程序。运行数据库服务器程序的机器,也称为应用服务器。一旦服务器程序被启动,就随时等待响应客户程序发来的请求;客户应用程序运行在用户自己的电脑上,对应于数据库服务器,可称为客户电脑,当需要对数据库中的数据进行任何操作时,客户程序就自动地寻找服务器程序,并向其发出请求,服务器程序根据预定的规则作出应答,送回结果,应用服务器运行数据负荷较轻。二、数据的储存管理功能较为透明。在数据库应用中,数据的储存管理功能,是由服务器程序和客户应用程序分别独立进行的,前台应用可以违反的规则,并且通常把那些不同的(不管是已知还是未知的)运行数据,在服务器程序中不集中实现,例如访问者的权限,编号可以重复、必须有客户才能建立定单这样的规则。所有这些,对于工作在前台程序上的最终用户,是“透明”的,他们无须过问(通常也无法干涉)背后的过程,就可以完成自己的一切工作。在客户服务器架构的应用中,前台程序不是非常“瘦小”,麻烦的事情都交给了服务器和网络。在C/S体系的下,数据库不能真正成为公共、专业化的仓库,它受到独立的专门管理。1.2.2HTTPHTTP(HyperTextTransferProtocol),超文本传输协议,是一种用于分布式、协作式和超媒体信息系统的应用层协议[1]。HTTP是万维网的数据通信的基础。HTTP是一个客户端和服务端之间请求和应答的标准,通常使用TCP协议。通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)。我们称这个客户端为用户代理程序(useragent)。应答的服务器上存储着一些资源,比如HTML文件和图像。我们称这个应答服务器为源服务器(originserver)。在用户代理和源服务器中间可能存在多个“中间层”,比如代理服务器、网关或者隧道(tunnel)。本系统采取C/S架构,其中客户端和服务端之间使用HTTP协议进行通信。系统开发相关技术概述1.3.1Java编程语言自推出至今,Java已经是用户最多的开发语言,其拥有面向对象、静态、可移植性等特点,特别适合用以开发健壮的程序。在服务端开发中,Java有着Spring的生态的强大以及其他许多优秀的开发框架,使用者非常多,技术有丰厚的沉淀。并且,基于Java静态和面向对象的特性,层次清晰,许多错误在编译时期就可以排除,特别适合大型服务器项目的开发。因此Java在服务器端开发占有非常大的比重。而在移动端的开发中,Android平台在市场上的占比超过一半,而Java作为Android应用开发的首选,其地位不可撼动。本系统基于C/S架构,Client端基于Android平台,Server端服务器中Spring生态下的Java是一个优秀的选择,因此整体的编程环境使用Java。1.3.2Android平台Android是一种基于Linux的自由及开放源代码的操作系统。主要使用于移动设备,智能手机和平板电脑,由Google(谷歌)公司和开放手机联盟领导及开发。在Google以Apache开源许可证的授权方式,发布了Android的源代码后,安卓系统得到的飞速的发展,市场份额迅速超过一半。目前市场上智能手机的操作系统99%为Andriod和iOS,除Apple公司外的智能手机基本都是使用户Android系统。由Android基于Linux并开放源代码,并且一直在更新和维护,拓展性优于封闭的iOS,许多开发者倾向于Android平台。Linux与其他操作系统一样,Android也采用分层的架构设计,从高到低分别是系统应用层(SystemApps),JavaAPI框架层(JavaAPIFramework),Android系统运行层(包括AndroidRuntime和原生态的C/C++库NativeC/C++Libraries)、硬件抽象层(HardwareAbstractionLayer)、Linux内核层(LinuxKernel)。其中的JavaAPI框架层,主要提供了构建应用程序时可能用到的各种API,开发者通过这一层的API构建自己的APP,所以Java也因此是开发Android程序的首选。1.3.3数据库 所谓“数据库”系以一定方式储存在一起、能予多个用户共享、具有尽可能小的冗余度、与应用程序彼此独立的数据集合,在大部分的软件开发中,数据库必不可少的组件。在服务端上,目前市场上主要流行着Oracle、SQLServer、MySQL等数据库,每种数据库都有其特点和优缺点,需要我们根据自身的需求去选择。Oracle能在所有主流平台上运行(包括Windows)。完全支持所有的工业标准。采用完全开放策略。可以使客户选择最适合的解决方案。Oracle支持多种工业标准,可以用ODBC、JDBC、OCI等网络客户连接。Oracle的产品可运行于很宽范围的硬件与操作系统平台上。可以安装在70种以上不同的大、中、小型机上;可在VMS、DOS、UNIX、WINDOWS等多种操作系统下工作。能与多种通讯网络相连,支持各种协议(TCP/IP、DECnet、LU6.2等)。提供了多种开发工具,能极大的方便用户进行进一步的开发。Oracle良好的兼容性、可移植性、可连接性和高生产率是OracleRDBMS具有良好的开放性。但是Oracle价格及其昂贵的,并且根据集群数价格越来越高。SQLServer是Microsoft推出一套产品,它具有使用方便、可伸缩性好、与相关软件集成程度高等优点,逐渐成为Windows平台下进行数据库应用开发较为理想的选择之一。SQLServer是目前流行的数据库之一,它已广泛应用于金融、保险、电力、行政管理等与数据库有关的行业。而且,由于其易操作性及友好的界面,赢得了广大用户的青睐,尤其是SQLServer与其它数据库,如Access、FoxPro、Excel等有良好的ODBC接口,可以把上述数据库转成SQLServer的数据库。SQLServer由于是微软的产品,它一般是和同是微软产品的.net平台一起搭配使用。因此其他平台上SQLServer的兼容性并不好。MySQL是最流行的关系型数据库管理系统之一,在WEB应用方面,MySQL是最好的RDBMS(RelationalDatabaseManagementSystem,关系数据库管理系统)应用软件。MySQL软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择MySQL作为网站数据库。正因为其社区版实开源免费的,所以非常适合作为小型应用的数据库。 因此,本系统首选MySQL作为服务端数据库。 但在客户端上,以上的数据库则显得略有笨重。本系统的每个模块基本都离不开本地数据库的使用,从服务端获取的常用的信息会保存到本地数据库,客户端本地产生的数据也会保存到数据库,而在安卓中最常用的就是SQLite。SQLite作为安卓内置的数据库,安卓已经为其提供了丰富的API接口,我们可以操作API或者可以像编写SQL语句那样操作数据库。所以在客户端上首选SQLite作为数据库。1.3.4Spring、SpringMVC框架结构及原理 Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由RodJohnson在其著作ExpertOne-On-OneJ2EEDevelopmentandDesign中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为J2EE应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。SpringMVC是Spring框架的一个模块,它实现了WebMVC设计模式,请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦。基于请求驱动指的就是使用请求-响应模型,能够简化服务器端的开发。1.3.5树莓派树莓派(RaspberryPi)是一款基于Linux的微型单片机计算机,能够完成大部分电脑能完成的事情。在本监控系统通过树莓派加上摄像头模块获取视频流,然后树莓派将视频流和其他传感器数据传输到服务器上。因为树莓派的运算力比普通的嵌入式设备要高,所以也可以在本地对原生数据进行处理。1.3.6NginxNginx同Apache、Tomcat一样,是一种服务器软件。它是一个高性能的HTTP向代理服务器,同时也是一个IMAP/POP3/SMTP理服务器。因此,使用Ngix可以搭建网站,也可以实现负载均衡的功能,还可以作为邮件代理服务器来接收和发送邮件。Nginx1.9.后的版本还可以作为通用的TCP/UDP理服务器,也可以提供一定的缓存服务功能。 那为什么选择Nginx作为本系统的流媒体服务器呢?性能好、占内存少和稳定作为流媒体服务器,相比Apache和其他服务器,Nginx占内存更少,使用效率更高,并且Nginx要比Apache更“轻量”,性能更好。功能强大Nginx提供了大量的功能模块,支持诸多特性,应用场景也多,可作为Web服务器、反向代理服务器,甚至也可以作为邮件服务器等。拓展性高Nginx的模块化设计极具拓展性,它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成的。因此,当对某一个模块进行缺陷修复或升级时,可以专注于模块自身,而不会影响其他模块。 这种低耦合度的设计,使得Nginx具有数量庞大的第三方模块。而且,我们后面也会用到其中的一个公开三方模块rtmp模块。1.3.7Rtmp协议RTMP协议是为了在AdobeFash平台技术(包括AdobeFlashPlayer和AdobeAIR)之间高性能传输音频/视频和数据而设计的。RTMP协议是一个开放的规范,通过此规范可以创建产品和技术,可以通过OpenAMF,SWF、FLY和F4V格式,提供与AdobeFlashPlay巳兼容的视音频和数据。关键特性:RTMP协议是应用层协议,需要靠底层可靠的传输协议(通常TCP)来保证信息传输的可靠性。在建立完基于传输层协议的链接后,RTMP协议也需要客户端和服务器端通过“握手”来建立基于传输层连接之上的RTMP连接。在连接上会传输一些控制信息,如SetChunkSize和SetACKWindowSize。其中CreateStream命令会创建一个Stream链接,用于传输具体的音频/视频等数据,以及控制这些信息传输的命令信息。RTMP协议在传输时会对数据进行格式化,这种被格式化的消息被称为RTMPMessage。而在实际传输时,为了更好地实现多路复用、分包和信息的公平性,发送端会把Message划分为带有MessageID的Chunk。每个Chunk可能是一个单独的Message,也可能是Message的一部分,在接收端会根据chunk中包含的data的长度、messageid和message的长度,把chunk还原成完整的Message,从而实现信息的收发。系统需求分析2.1系统的功能需求分析概述用户启动移动端程序并登录后进入主界面,主界面是不同功能的入口,分别是摄像头监控、婴儿数据管理和婴儿时间表,点击后进入对应的功能页面。一、摄像头监控。进入后可打开用户家的婴儿床的摄像头,然后可以实时看婴儿的视频。 二、婴儿任务提醒。用户可提前制定一个时间表,例如“12时00分喂奶”这样的计划,然后软件自动提醒用户执行。2.2系统功能分析 根据以上对用户的需求分析可以得出婴儿监控App(以下简称App)如下: 登录功能是此类需要验证用户合法性软件必不可少的功能,用户只能访问自己家的婴儿床监控系统,所以需要一个权限校验的功能。 登录后根据不同的功能和服务端建立连接,发起不同的请求,若是请求的视频,则建立长连接,传输视频流。若是请求普通数据,则建立短连接,传递JSON数据。系统的设计开发严格遵循软件工程规范,选择需要的软件设计模式,减少系统各个模块之间的耦合程度。本App主要功能模块如下:权限校验模块,区分不同的用户及对应权限。视频模块,解析从服务器请求的视频流,播放视频。数据管理模块,将数据进行处理和展示。时间表模块,根据用户定制的时间任务,提醒用户执行。服务端程序则是为App提供远程的服务,根据App和树莓派发来的不同请求作出不同的响应。服务端的对应功能逻辑如下:登录,权限校验。通过查询数据库进行用户身份和权限校验。视频接受与推送。接收树莓派采集上传的视频流,推送到App。数据管理。接收并处理树莓派上传的数据,用户请求对应数据系统设计3.1系统数据库设计3.1.1用户信息表结构设计 用户信息表用于保存注册的用户的信息,字段包括用户的id(主键)、账号、密码等个人信息。表结构如表3.1所示:Tableuser字段名称数据类型字段长度是否为空说明idbigint30No主键usernamevarchar30No账号passwordvarchar30No密码nicknamevarchar30Yes昵称sexbit1No性别ageint8Yes年龄表婴儿信息表结构设计Tablebaby字段名称数据类型字段长度是否为空说明idbigint30No主键namevarchar30No姓名sexbit1No性别birthdatedate0No出生日期表用户-婴儿关系表结构设计Tableuser_baby字段名称数据类型字段长度是否为空说明useridbigint30No用户主键babyidbigint30No婴儿主键表用户-硬件关系表结构设计Tableuser_hardware字段名称数据类型字段长度是否为空说明useridbigint30No用户主键hardwareipvarchar30Yes硬件ip表3.43.2移动端系统的设计3.2.1注册模块设计 用户第一次使用此手机软件时,需要先注册一个账号才能继续使用。注册界面需要用户填写用户名(账号)和密码作为唯一凭证,然后首先客户端会对账号和密码进行合法性校验。用户名要求非空,以字母开头,长度4-12个字符,允许字母数字下划线;而密码则要求以字母开头,长度6-18个字符,只能包含字母、数字和下划线。校验文本是否满足规则常用的方法是使用正则表达式匹配,根据以上规则,可以很简单得出账号规则的正则表达式为公式3.2.1,密码的正则表达式为3.2.2。 ^[a-zA-Z][a-zA-Z0-9_]{3,11}$ 式3.2.1^[a-zA-Z]\w{5,17}$ 式3.2.2 以下是具体判断的代码:publicbooleanisUserNameAndPwdValid(){Stringusername=accountEditTest.getText().toString();Stringpassword=passwordEditTest.getText().toString();//获得账号的正则表达式对象及匹配器Patternpattern=Ppile("^[a-zA-Z][a-zA-Z0-9_]{3,11}$");Matchermatcher=pattern.matcher(username);if(!matcher.matches()){Toast.makeText(this,getString(R.string.username_invalid),Toast.LENGTH_SHORT).show();returnfalse;}//获得密码的正则表达式对象及匹配器pattern=Ppile("^[a-zA-Z]\\w{5,17}$");matcher=pattern.matcher(password);if(!matcher.matches()){Toast.makeText(this,getString(R.string.password_invalid),Toast.LENGTH_SHORT).show();returnfalse;}returntrue;}本地合法性校验通过后,将用户名和密码发送到服务端,服务端再对账号和密码进行数据库校验。若校验成功,客户端将会收到服务端的响应回来的成功信息,若失败,则会收到响应回来的错误信息,这时候客户端则需要提醒用户错误的原因,然后重新输入。 当注册成功后,则需要继续完善个人信息,例如昵称、性别、年龄等信息,填写成功后,则完成整个注册流程,跳回登录页面。3.2.2通信模块设计 上文提到,当点击注册时,会向服务器发送请求,然后服务端去查数据库。服务端查完数据库后,会将结果相应回客户端。在本系统,客户端和服务端通过HTTP协议进行通信。手机App作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求,Web服务器根据接收到的请求后,向客户端发送响应信息。不仅仅是注册,许多功能都需要访问服务器,而安卓原生的发情网络请求的HttpUrlConnection以及ApacheHttpClient,在使用步骤和使用细节上都比较繁琐和麻烦,所以本系统使用安卓端最火热的轻量级框架,由移动支付Square公司贡献的OKHTTP网络框架。 本系统用到的HTTP请求主要有Get请求和Post请求,而OkHttp中发起Get和Post的流程必将相似,都为“创建OKhttp客户端—创建Handler回调对象处理业务—创建请求对象—创建Callback回调对象处理响应”,唯一的区别是Get请求的请求参数是通过将参数拼接到URL后,而POST是通过创建请求实体对象传递,所以可以创建一个工具类封装Get请求和Post请求的方法,达到代码复用的目的。以下是RequestUtil中对Get请求的封装:①Get请求处理参数publicstaticvoidget(Handlerhandler,Stringurl,Map<String,String>map){StringBuildertempParams=newStringBuilder();try{//处理参数intpos=0;for(Stringkey:map.keySet()){if(pos>0){tempParams.append("&");}//对参数进行URLEncodertempParams.append(String.format("%s=%s",key,URLEncoder.encode(map.get(key),"utf-8")));pos++;}//补全请求地址if(pos>0){tempParams.insert(0,url+"?");}StringrequestUrl=tempParams.toString();sendGetRequest(handler,requestUrl);}catch(Exceptione){Log.e("GET请求出错",e.toString());}}其中,第一个参数Handler是发起请求线程的回调对象,在异步请求请求成功后执行。②发送请求方法publicstaticvoidsendGetRequest(Handlerhandler,Stringurl){StringfullUrl=ConstantUtil.BASE_URL+url;OkHttpClientclient=newOkHttpClient();Requestrequest=newRequest.Builder().url(fullUrl).build();creatNewCall(client,request,handler);}③创建Callback对象回调处理相应方法privatestaticvoidcreatNewCall(OkHttpClientclient,Requestrequest,Handlerhandler){client.newCall(request).enqueue(newCallback(){@OverridepublicvoidonFailure(Callcall,IOExceptione){}@OverridepublicvoidonResponse(Callcall,Responseresponse)throwsIOException{Messagemsg=newMessage();try{if(response.isSuccessful()){//回调的方法执行在子线程。Mapresult=JSON.parseObject(response.body().string(),Map.class);if((boolean)result.get("success")){msg.what=1;}else{ //-2代表业务逻辑错误msg.what=-2;} msg.obj=result;}else{msg.what=-1; } }catch(Exceptione){ e.printStackTrace();//使用-1代表程序异常msg.what=-1;msg.obj=e;}handler.sendMessage(msg);}});} 此处的Callback对象也是用来回调处理,但与之前的Handler不同,Callback是在请求的线程中调用,主要是用来处理响应信息,而Handler则是发起请求的线程中调用,主要是用来处理得到响应后的业务逻辑,而这两个线程之前则需要通过Message对象进行线程中的传递信息。先用Message对象进行获取相应信息,并传回给调用该方法的线程。并在在默认的处理中,定义了几个数字常亮代表不同的状态,1代表请求成功,并封装成功的业务信息;-2代表请求成功,但封装的是失败的业务信息;-1代表请求出现异常,并封装异常信息。 解决完如何发送请求后则是解决如何接收服务端传递回来的数据的问题。目前常用的一种传递数据的方式是服务端将数据解析成JSON格式,然后客户端通过JSON解析工具将JSON数据转换回JavaBean、Map、List或其他对象形式。本系统选用Alibaba的fastjson工具类进行转化,以下以注册模块代码为示例。服务端通用传输对象@Getter//此注解为Lombok工具提供,作用是自动生成所有属性的getter方法publicclassJsonResult{privatebooleansuccess=true;privateStringmsg;privateObjectresult;publicJsonResultmark(Stringmsg){this.success=false;this.msg=msg;returnthis;}publicJsonResultsetResult(Objectresult){this.result=result;returnthis;}……}此工具类是服务器传输数据的通用对象,如果业务逻辑成功,则调用setResult()方法将要传输数据的数据设置到对象中;如果业务逻辑失败,则调用mark(Stingmsg)方法将错误信息设置到对象中,方法内部将标志位success设置为false。最终服务端将JsonResult对象转换为json格式响应给客户端。接收解析json数据在3.2.2中的第②部分代码中,在处理相应的时候利用FastJson解析JSON解析为Map对象并封装到Messager中.Mapresult=JSON.parseObject(response.body().string(),Map.class);……msg.obj=result;处理业务逻辑publicvoidhandleMessage(Messagemsg){Mapresult=(Map)msg.obj;switch(msg.what){case-1:Toast.makeText(RegisterActivity.this,"服务器连接失败!",Toast.LENGTH_SHORT).show();break;case-2:Toast.makeText(RegisterActivity.this,(String)result.get("msg"),Toast.LENGTH_SHORT).show();break;case1:Toast.makeText(RegisterActivity.this,"注册成功",Toast.LENGTH_SHORT).show();Intentintent=newIntent(RegisterActivity.this,LoginActivity.class);startActivity(intent);finish();}}HandleMessage(Messagemsg)是Handler对象中要覆写的方法,会在请求成功后被回调执行。之前在对OkHttp作请求封装时,对Message对象进行了一些默认设置,msg.what=1代表正常,成功;-1代表请求失败;-2代表请求成功,业务逻辑失败。所以在这里可以通过判断不同的状态码编写接下来的行为。通常上述代码中case1:的情况,3.2.3登录模块设计 程序启动时,首先显示的界面便是登录界面,若不能完成登录,则不能访问之后的所有功能。因此,登录界面和逻辑的设计的友好型在一定程度上影响着用户对本系统的兴趣。 登录界面需要填写已经注册过的账号和密码,点击登录后将客户端将像之前注册一样,现在客户端内进行合法性校验,如果不通过校验则直接返回错误信息提醒用户,而不用发送请求到服务端和数据库,这样能够大大减少响应时间以及服务器和数据库的流量和压力,也能使程序看上去更加流畅,提高用户的好感度。在请求登录成功后,得到服务器返回的登录信息,然后跳往主页HomeActivity。switch(msg.what){……case1: ……storage(user);//登录成功后保存登录信息Intentintent=newIntent(LoginActivity.this,HomeActivity.class);startActivity(intent);//关闭当前界面finish();}3.2.4视频模块设计视频模块主要功能是获取树莓派摄像头的实时影像,并且通过播放器展示给用户。用户在主页可以点击打开监控的图标,然后就会跳转到播放器页面进行播放。摄像头采集数据后会以RTMP协议推流到服务器,因此在客户端只需要知道硬件推流的地址然后以RTMP协议获取视频流,然后再根据视频的编码格式进行解码播放。这是具体的设计思路,在1.3.6章中有队RTMP协议的介绍。不过如果需要手动解码RTMP那可能会非常复杂且工作量大,所以本系统使用一款Android/iOS都十分热门的多媒体开发框架。Vitamio支持海量的视频格式及协议,还可以在Android与iOS上跨平台支持MMS,RTSP,RTMP(本系统推流的协议),HLS(m3u8)等常见的多种视频流媒体协议,包括点播与直播。并且其API简洁易用,所以本系统将VitamioSDK开发平台完成视频模块的设计。使用Vitamio第一步是集成Vitamio到App。由于本系统是以AndroidStudio开发的,所以先是在AndroidStudio中importmodule选择Vitamio项目,然后在app中的gradle中引入该包的依赖。第二步则是对Vitamio项目中的compileSdkVersion、minSdkVersion、targetSdkVersion版本改成跟自身项目一致。第三步则是在项目的AndroidManifest.xml中注册Vitamio中“io.vov.vitamio.activity.InitActivity”组件,并且开启应用的Internet、wake_lock、access_network_state、和read_external_storage权限,具体作法是在AndroidManifest.xml文件中添加以下几行配置:<uses-permissionandroid:name="android.permission.INTERNET"/><uses-permissionandroid:name="android.permission.WAKE_LOCK"/><uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>以及<activityandroid:name="io.vov.vitamio.activity.InitActivity"android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"android:launchMode="singleTop"android:theme="@android:style/Theme.NoTitleBar"android:windowSoftInputMode="stateAlwaysHidden"/>至此,Vitamio便是引入成功。引入成功后便是先在布局文件中引入播放器空间<LinearLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.belcheri.myapplication.VideoActivity"><RelativeLayoutandroid:id="@+id/rela"android:layout_width="match_parent"android:layout_height="match_parent"><io.vov.vitamio.widget.VideoViewandroid:id="@+id/vitamio_videoview"android:layout_width="match_parent"android:layout_height="match_parent"/></RelativeLayout></LinearLayout> 其中,核心控件是io.vov.vitamio.widget.VideoView,这是一个播放器控件,而RelativeLayout则是为了使进度条和播放器的位置重合不分离。 布局完成后开始编写VideoActivity,使用vitavio的播放器需要在视频播放的ActivityonCreate中setContentView()之前添加解码监听判断,用以检查vitamio框架是否可用。publicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_video);Vitamio.isInitialized(this);//检查框架是否可用initView();//初始化视图控件initData();//初始化数据}然后就是初始化视图控件和数据privatevoidinitData(){mVideoView.setVideoURI(Uri.parse(url));mVideoView.setMediaController(newMediaController(this,true,mRelatviLayout));//设置监听mVideoView.setOnPreparedListener(this);mVideoView.setOnErrorListener(this);mVideoView.setOnCompletionListener(this);}privatevoidinitView(){mVideoView=findViewById(R.id.vitamio_videoview);mRelatviLayout=findViewById(R.id.rela);}最后实现MediaPlayer类中的三个接口OnPreparedListener,OnErrorListener,OnCompletionListener以及覆写对应的方法。@OverridepublicvoidonPrepared(MediaPlayermp){Toast.makeText(this,"准备好了",Toast.LENGTH_LONG).show();mVideoView.start();}@OverridepublicvoidonCompletion(MediaPlayermp){Toast.makeText(this,"播放完成",Toast.LENGTH_LONG).show();}@OverridepublicbooleanonError(MediaPlayermp,intwhat,intextra){Toast.makeText(this,"Error",Toast.LENGTH_LONG).show();//返回truereturntrue;}@OverrideprotectedvoidonDestroy(){super.onDestroy();mVideoView.stopPlayback();}最终整体结构如下publicclassVideoActivityextendsAppCompatActivityimplementsMediaPlayer.OnPreparedListener,MediaPlayer.OnErrorListener,MediaPlayer.OnCompletionListener{privateVideoViewmVideoView;privateRelativeLayoutmRelatviLayout;publicvoidonCreate(BundlesavedInstanceState){…}privatevoidinitData(){…}privatevoidinitView(){…}publicvoidonPrepared(MediaPlayermp){…}publicvoidonCompletion(MediaPlayermp){…}publicbooleanonError(MediaPlayermp,intwhat,intextra){…}protectedvoidonDestroy(){…}} 但竖屏观看视频的体验并不好,用户在看视频的时候往往会选择横屏全屏观看,在这种情况下,我们需要监控手机的旋转情况,当手机切换成水平\竖直放置时候,自动切换布局。 所以为了完善这个需求,首先得监控手机的信息,所以要在当前activity上增加一行配置:<activityandroid:name=".VideoActivity"android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"/>添加完之后就可以在VideoActivity中获取手机的信息,然后修改页面布局,具体代码如下:publicvoidonConfigurationChanged(ConfigurationnewConfig){//屏幕切换时,设置全屏if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE){setFullScreen();}else{LinearLayout.LayoutParamslayoutParams=newLinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,600);mRelatviLayout.setLayoutParams(layoutParams);RelativeLayout.LayoutParamslayoutParams1=newRelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT);mVideoView.setLayoutParams(layoutParams1);}super.onConfigurationChanged(newConfig);}privatevoidsetFullScreen(){Log.d("haha","调用设置全屏");LinearLayout.LayoutParamslayoutParams=newLinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);RelativeLayout.LayoutParamslayoutParams1=newRelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT);mRelatviLayout.setLayoutParams(layoutParams);mVideoView.setLayoutParams(layoutParams1);}添加完上述代码后,便完成了看视频时候横屏全屏的需求,效果图如图3.1、3.2所示。图3.1竖屏播放效果图图3.2横屏播放效果图 视频模块的功能的使用,需要用户有访问其摄像头的权限,所以在点击跳转前,还要额外发送请求到服务端,获取用户权限,以及对应硬件的IP地址。若有权限,则跳转,若没有权限,则提示用户,然后留在Home页面。3.2.5任务提醒模块设计 照顾婴儿是一件很累人的事情,许多家长在这个过程中忙的头昏眼花;又或是有的家长忙于其他事情,偶尔会忘记或迟了做给婴儿喂奶等事情。所以本系统有一个能快速提醒用户任务的功能。它将常见的照顾婴儿要做的事情整理出来,用户只需要选择时间,然后设定提醒时间,手机便会在制定的时间到了的时候响起,并且画面提醒你需要执行的任务,大概的流程如上面所说。 具体实现:当用户点击定时任务功能时候,程序就会跳转到对应的ClockActivity,并切换到对应的activity_clock.xml布局,并且通过调如下代码获取全局的定时器。alarmManager=(AlarmManager)getSystemService(Context.ALARM_SERVICE);定时任务界面主要包含两个元素:若干个已经定义好事件意义的按钮和已经设定好的事件列表。事件按钮通过<button>标签进行布局,而事件列表由于事件是通过查数据库查出来的,所以需要通过在.java中通过代码实现。所以在切换到activity_clock.xml布局前,需要先在ClockActivity.onCreat()方法中,通过SQLite查询客户端本地的数据库,然后再将数据遍历设置到布局中。而将数据遍历到布局可以使用<ListView>配合Adapter实现,具体代码如下所示:publicvoidqueryMyClock(Viewv){MySQLiteOpenHelpersqLiteOpenHelper=newMySQLiteOpenHelper(getApplicationContext());SQLiteDatabasedatabase=sqLiteOpenHelper.init();if(!DbUtils.tabIsExist("myclock",sqLiteOpenHelper)){ClockController.createTable(database);}ListViewlistView=(ListView)findViewById(R.id.clocklist);MyAdapteradapter=newMyAdapter(getApplicationContext(),getClockList(),R.layout.my_clock_list);listView.setAdapter(adapter);} 其中类MyAdapter是一个继承BaseAdapter的自定义类,通过覆写对应的方法getView()订制将数据设置到ListView的规则,并且<ListView>中的数据布局方式是引用的R.layout.my_clock_list的布局文件。publicViewgetView(intindex,Viewview,ViewGrouparg2){//中间变量finalintflag=index;//给xml布局文件创建java对象LayoutInflaterinflater=LayoutInflater.from(context);view=inflater.inflate(resource,null);//指向布局文件内部组件TextViewtext=(TextView)view.findViewById(R.id.my_clock);Buttonbtn=(Button)view.findViewById(R.id.delBtn);Map<String,Object>map=dataList.get(index);btn.setTag(map.get("id"));text.setText(map.get("mission").toString());btn.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){ClockController.deleteClock(Long.valueOf(map.get("id").toString()),newMySQLiteOpenHelper(context));dataList.remove(index);MyAdapter.this.notifyDataSetChanged();}});returnview;} 上述代码是getView的具体实现,可以看到,getView在往<ListView>中设置数据后,并且还个体每一行的删除按钮绑定一个点击事件,在点击后先从标签中获取所点击的按钮的tab,并根据tab从数据库中删除所点击的列,并且将渲染数据的列表内的响应数据移除,然后刷新变化。 在显示完任务列表后,用户可以通过点击对应的事件按钮添加新的任务。点击后会弹出一个设置任务事件的界面,然后在界面选择任务触发事件,按确定便完成设置。下面将抽取部分代码解释实现过程。publicvoidsetClock(Viewv){intviewId=v.getId();intthing;switch(viewId){caseR.id.feed_milk:thing=0;break;caseR.id.change_diapers:thing=1;break;default:thing=-1;}queryMyClock(null);Toast.makeText(ClockActivity.this,"设置闹钟",Toast.LENGTH_SHORT).show();Dialogdialog=newTimePickerDialog(ClockActivity.this,newTimePickerDialog.OnTimeSetListener(){@OverridepublicvoidonTimeSet(TimePickertimePicker,inthourOfDay,intminute){Calendarc=Calendar.getInstance();//获取日期对象c.setTimeInMillis(System.currentTimeMillis());//设置Calendar对象c.set(Calendar.HOUR_OF_DAY,hourOfDay);//设置闹钟小时数c.set(Calendar.MINUTE,minute);//设置闹钟的分钟数c.set(Calendar.SECOND,0);//设置闹钟的秒数c.set(Calendar.MILLISECOND,0);//设置闹钟的毫秒数MySQLiteOpenHelpersqLiteOpenHelper=newMySQLiteOpenHelper(getApplicationContext());SQLiteDatabasedatabase=sqLiteOpenHelper.init();if(!DbUtils.tabIsExist("myclock",sqLiteOpenHelper)){ClockController.createTable(database);}ClockController.addClock(newSimpleDateFormat("HH:mm:dd").format(c.getTime()),sqLiteOpenHelper,thing);Intentintent=newIntent(ClockActivity.this,AlarmReceiver.class);PendingIntentpi=PendingIntent.getBroadcast(ClockActivity.this,MyClock.getClockCode(),intent,PendingIntent.FLAG_CANCEL_CURRENT);//设置一次性闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟//执行时间,第三个参数表示闹钟响应动作。if(c.getTimeInMillis()<System.currentTimeMillis()){Log.i("clock","设置时间要推迟24小时,不然立刻会响");alarmManager.set(AlarmManager.RTC_WAKEUP,c.getTimeInMillis()+24*60*60*1000,pi);}else{alarmManager.set(AlarmManager.RTC_WAKEUP,c.getTimeInMillis(),pi);//设置闹钟,当前时间就唤醒}queryMyClock(null);Toast.makeText(ClockActivity.this,"任务设置成功",Toast.LENGTH_LONG).show();//提示用户}},calendar.get(Calendar.HOUR_OF_DAY),calendar.get(Calendar.MINUTE),false);dialog.show();} 首先通过点击按钮的i
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 南京市严查人脸考勤制度
- 北京特殊天气考勤制度
- 大学班级上课考勤制度
- 中职学校职工考勤制度
- 工地工人打卡考勤制度
- 公司为何重视考勤制度
- 卫生院考勤制度管理规定
- 家政小时工考勤制度范本
- 医院进修人员考勤制度
- 传媒公司作息考勤制度
- 终止合同通知书
- DZ∕T 0345-2020 煤炭矿区地质勘查成果总结报告编写规范(正式版)
- 踝关节骨折LaugeHansen分型课件
- 国际大奖小说傻狗温迪克
- 15D502 等电位联结安装
- 成人有创机械通气气道内吸引技术操作解读-
- 标志桩安装质量评定表
- 初高中数学衔接讲义
- 安徽杭富固废环保有限公司10万吨工业废物(无机类)资源化利用及无害化处置项目环境影响报告书
- 多学科设计优化综述
- mcn机构的通讯录
评论
0/150
提交评论