“亲子安全卫士”项目总结
零.开发环境与工具
系统:liunx
开发环境:android studio
线上合作工具:git,Tower
一.项目过程
1.确定需求,需求文档编写
2.设计师给出设计
3.安卓端前端界面实现
4.安卓端代码编写,后台代码编写
5.测试,维护,发布
这里着重介绍安卓端的界面与逻辑的代码编写过程:
首先,我们确定了这个APP的大致框架,确定了各个包:存放各个窗体活动类的Activity包,存放listview适配器类的Adapter包,存放用户信息类的bean包(该用户类用于填充list容器,并将该容器填充至listview中),存放常量类的CommonParameter包,存放自定义控件的Custome包,存放各个数据库操作类的DataBase包,存放安卓后台服务组件的Services包,存放与服务器通信的线程类的Thread包和存放各个工具类的Utils包.
随后,开始了前端界面的编写:
1.根据设计稿,创建了各个活动窗体,对于相应的窗体,创建了相应的layout.xml文件,在xml文件中按照设计编写出相应的前端界面.如,登陆界面,注册界面等
2.之后,设计欢迎界面:在layout文件中放置背景图,在indexactivity.java中编写淡入动画的业务逻辑:通过子线程与主线程循环发送消息的方法,每隔一段时间发送一次信息,主线程调用p_w_picpathview的渐变函数,实现淡入动画的效果
3.然后,自定义listview,设计下拉刷新效果.
4.随后,设计管理者界面:这里用到了自定义listview的adapter目的是方便自行编写每个条目内部控件的各种事件,自定义item.xml,使listview的每个条目通过LayoutInflater加载该文件.
第三,进行本地数据存储与业务逻辑的处理
1.利用android自带的SQLite API,封装database类,对外提供建表,数据查询,数据更新,插入,删除操作.
2.优化listview的adapter实现,用viewHolder作为容器存放控件,通过settag和gettag方法,根据需要动态加载layout文件,达到内存优化的目的.
3.编写用于记录用户登录状态的文件存储类,提供了,写入,更新,删除接口.
4.编写用于获取本机状态信息(本机时间,本机号码,设备名称,设备ID等)的本机信息类.
5.编写自定义对话框类,通过layoutinflater加载视图,对外暴露对话框的常用接口,随后,利用在适宜处使用该对话框类,添加了点击后的监听事件.
6.编写用于http请求的工具类
7.增加了点击修改备注名的操作,增加了不在线显示灰色头像的处理
8.根据需求特点,使被管理者界面继承管理者界面,被管理者界面的适配器继承自管理者界面的adapter
9.导入百度地图sdk,对外提供本机地理位置获取,经纬度转换成文字,经纬度地图显示的接口.
第四,根据后台与安卓端数据通信文档,编写相应的客户端请求代码
1.按照模板方法模式,编写线程请求模板,不同子线程类,跟基类线程,仅仅是返回字符串的不同.
2.为登陆注册编写相应的客户端请求逻辑,提供请求参数,处理返回字符串,子线程与UI线程通过adroid自带的handler类进行通信.
3.按照先前的请求处理模板,编写与后台通信并处理联系人列表
4.处理下拉刷新后的服务器请求逻辑
5.依照先前的请求模板,编写注销,二次登陆与修改备注名.自定义popupwindow控件编写点击菜单事件
6.编写轮询线程,编写相应的service,用来开启轮询线程,向服务器不断发送请求.在service组件设置handler用来与轮询线程通信,然后相应的activity设置handler用于与service之间数据交互.
7.编写用于实现获取对方地理位置的请求逻辑,和让对方反拨电话的请求逻辑
8.测试与bug修复
二.项目难点
1.卡片式listview的实现:
描述:根据这个项目的需求特点,每个listview的条目是由多个控件复合而成,每个条目的内部控件都有监听事件,普通的adapter对于这样的listview并不适用.
解决办法:继承自BaseAdapter,自定义listview的adapter.
具体实现方法:用一个list容器存放用于描述各个用户信息的bean类,把该list作为参数传递给adapter.用viewholder类存放各个控件,在getview方法中,通过layoutinflater,settag,gettag方法加载xml视图并动态加载viewholder中的各个控件.各个条目的信息事先通过sqlite进行本地存储,getview被系统调用以后,从数据库中加载相应的用户信息
2.本机地理位置获取不稳定问题:
描述:利用安卓sdk自带的user location接口获取本机的地理位置误差大,不稳定,经常包空指针错误.
解决办法:调用百度地图提供的免费api,获取开发者key,同时解决了获取地理位置,经纬度转换文字,经纬度百度地图显示的问题.
3.多个线程同时请求服务器造成的紊乱问题:
描述:当有多个线程请求服务器的时候,会报告线程同步错误
问题原因:利用单例模式创建httpclient对象的时候传递的SimpleClientConnManager对象并不是线程安全的.
解决办法:舍弃SimpleClientConnManager,改用线程安全的ThreadSafeClientConnManager
4.初次请求ThreadSafeClientConnManager服务器的联系人列表的加载问题:
描述:联系人列表在启动app的时候是首先从本地缓存获取数据的,随后,客户端自动向服务器发送请求,更新联系人列表数据.本地缓存解决了在网络不好的情况下的联系人列表的加载问题.但是,初次启动时,本地缓存并没有数据,只能从服务器获取.
解决办法:存储状态信息,设置数据加载界面
具体措施:利用sharedpreferences存储用户的登陆状态,即是初次登陆还是再次登陆.对于初次登陆,界面切换到数据加载界面,如果由于网络原因,初次加载失败,再次加载的时候,就再次出现该数据加载界面,直到初次加载成功为止,之后,不再出现数据加载界面,直接首先从本地缓存读取数据.
5.服务器无法主动给对方发送信息的问题:
描述:正常情况下,管理者想要主动获取被管理者的地理位置的时候,需要先向服务器发送信息,然后服务器”告诉"被管理者,管理者想要获取你的位置.而对于http协议,务器是没有办法主动发送消息给客户端的.如果采取被管理者不断向服务器上传数据的方法,会造成大量的流量和电量损耗.
解决办法:双方在上线之后开启轮询线程,不断请求服务器,在无事状态下,服务器返回”n”字段,在对方有获取地理位置的请求的时候,服务器返回”location”字段,客户端调用百度地图sdk获取本机位置在下一次轮询的时候,将自己的地理位置传给管理者,管理者在下一次轮询的时候,得到对方传递的地理位置信息.
6.有些设备本机号码无法获取问题:
解决办法:在初次登陆的时候,如果设备获取不到本机号码的时候,弹出对话框,需要用户手动输入本机号码,用正则表达式匹配字符串为11位数字,防止用户乱输入.
三.项目亮点
1.设计模式的合理使用
在创建httpclient对象的时候,使用了单例模式,符合逻辑,节省内存;在设计http请求线程的时候,用到了模板方法模式,增强了代码的复用性,体现了面向对象的思想
2.工具类的合理编写
Utils包中定义了,用于实现http请求过程的httpUtils类,将得到服务器返回字段的主要方法对外开放,将其他请求过程分隔函数,对外关闭;还有用于文件缓存的UserInfoUtils类,利用java的IO操作,以键值对的形式将用户信息以字符串的形式存储,通过”#”来分隔,同样地,将增删改查,操作对外开放,将io流的内部操作对外关闭.
3.合理的通过自定义控件来满足需求.比如,自定义listview,增加顶部视图和下滑手势的监听事件,达到下拉刷新的效果;自定义对话框,加载自定义对话框视图,使得对话框能够采用由自己设计的样式.\
四.项目不足
1.继承使用的不合理
两个adapter,虽然功能相似,但是manageradapter类相当”具体”,拥有复杂的属性和方法,对于相当庞大和具体的类.使用继承,造成的构造方法调用混乱,权限修饰符使用不合理,并未起到增加代码服用性的效果,反而增加了维护的难度。
2.两个activity过于庞大,冗长
将过多的逻辑处理和状态存储与读取放到两个activity中,其中,相似代码较多,尤其是处理各个请求的handler并没有分类处理,造成activity类过于冗长。对于每个thread相应的handler,逻辑处理相似,只是返回值不同,可以按照相似的模板方法模式,单独分包,通过传递消息(参数)的方式,来调用相应的方法更新UI
3.个别地方用户体验不好
文本输入框没有合理缩进,提示信息不明显,没有考虑到没有菜单键的用户
五.个人心得体会
这个项目是我大二寒假与大二下期开学一个月的时候做的,算是本人第一个相对比较正式的项目吧,做这个项目之前,对于编程的理解还处于特别肤浅的阶段,只注重功能实现,不关注代码复用性,和性能优化问题,甚至对一些java基础的知识还比较茫然,对于面向对象的理解还处于,封装类、分隔函数、分支、循环、传参调函数的阶段。所以,尽管自己全程参与了这个项目,但是还有很多代码编写不合理的地方。这个项目,让我认识到了我的java基础的薄弱,面向对象思想的缺乏,以及对安卓应用程序框架理解的浅显,让我在接下来的时间,明确了学习的重点和工作的主次,同时,也坚定了我在技术道路越走越远的决心。