最近在组建项目组从0开始开发项目,从立项到上线,有一些心得,包括项目规范、结构、优化、三方等,与大家分享,一起修仙! 接下来我会以自己写的两个项目为例,结合起来分析。代码已经上传github: Material Design风格项目 点击前往 喜欢就给个star^_^ UI、Base、网络等封装库项目 点击前往 喜欢也给个star喽 先上图来看看吧: 项目采用MVP+Retrofit+RxJava+Gson+Glide+Material Design 设计 同时也使用了EventBus事件总线 、GreenDao数据库 、SurfaceView+MediaPlayer视频播放器 等主要技术。 ok!项目就简单介绍到这里,接下来开始我们的修仙之路。 1、项目整体分析 a、UI风格 logo 主题风格: Material Design 仿ios 主界面–侧拉 主界面–仿微信 选项卡等 b、技术方案 整体分析项目,确定整体技术方案,之后的开发中按照技术方案执行,同时编写相关文档。 项目架构 网络框架 图片处理 数据处理/接口格式 三方使用:统计、推送、更新等 c、可行性分析 邀请项目经理、技术负责人、产品经理、后端开发、测试等共同分析技术方案的可行性,并相应调整技术方案。 d、工期 根据项目需求和技术方案,给出开发时长; 根据工期要求,可适当调整技术方案。 e、测试用例 测试人员开始整理、编写测试用例和项目标准文档; 个人觉得开发人员应该参与到测试工作中,这样方便自己对业务逻辑和功能分析全面,也帮助测试人员分析项目功能和技术,便于写出更加全面的测试用例。 2、开发规范 其实Android、Ios、Server等各端开发人员,都应该有完整的、严格的开发规范,这里我只说一下Android端的开发规范: 以自己项目为例,涉及到以下几项: 文档规范 资源命名规范 代码命名规范 代码注释规范 代码风格规范 服务器数据规范 等 a、文档 重要有以下几个文档: 需求文档 产品原型图 完整UI图 接口文档 核心技术文档 重点逻辑文档 程序框架图 ER图、数据字典、类图等 测试文档 b、资源文件命名规范 名字全部小写,最好不用数字,全部英文,单词中间下划线隔开 ~、drawable、anim等文件夹下 名称结构为“技术点模块点 空间类型_功能名”结构,技术点主要有:selector、translate、alpha、scale等,模块名主要有:login、pay、mine、setting等,控件类型主要有:button、textview、imageview、dialog等,功能名主要有:findpwd、request、back、next等。
~、drawable-xhdpi等图片资源 名称为“技术点模块点 功能名”结构,技术点主要有:activity、fragment、item、include等,模块点主要有:login、setting、mine、pay等,功能名主要有:head、title、back、sure等。
~、layout 布局名称为“技术点模块 功能名”结构,技术点主要有:activity、fragment、item、include等,模块主要有:home、lesson、mine、loginregist等,功能名主要有:login、title、setting、pay、bar等。
~、values 布局名称为“技术点模块 功能名”结构,技术点主要有:activity、fragment、item、include等,模块主要有:home、lesson、mine、loginregist等,功能名主要有:login、title、setting、pay、bar等。
c、代码命名规范 ~、包名 包名为“根包名.技术点名.模块名”结构,全部小写
~、类名 采用 大驼峰 命名法,单词直接拼接,所有单词首字母大写 类名为“业务模块名 执行操作名 技术点名”结构,业务模块名主要有:home、lession、net、login,pay等,操作名主要有:Get、Set、Request、Login等,技术点名主要有:Activity、Fragment、View、Adapter等。
~、普通变量 采用 小驼峰 命名法,第一个单词首字母小写,其他单词首字母大写。 普通变量为“名字简写 类型 功能名”结构,名字简写有:js等,类型主要有:Int、Double、Boolean、String、Char等,功能名有:Login、Number、Content等。
~、常亮 所有字母全部大写,中间下划线隔开 常量为“功能名_标识”结构,功能名主要有:LOGIN、REQUEST、PERSONINFO等,标识有SUCCESS、ERROR、URL等。
~、方法名 名字能体现出功能即可。不再累赘重述。
3、数据/接口定义 建议 服务器返回数据采用json格式 json数据中无数据,必须返回空数组或空字符串,不可返回null Android端使用gson或fastjson或jackson等三方解析工具解析 不建议使用官方JSONObject解析,容易出错 实体类属性名与json中字段名完全一致 json中字段名全部使用英文,不可英文、拼音夹杂 用户表识建议使用Cookie 建议使用POST解析,它对参数数量没有要求,也比较安全 为了传输安全,使用https请求 等 完善接口文档,建议每一版对应一个完整接口文档 4、屏幕适配 安卓设备分辨率、屏幕尺寸五花八门,碎片化严重,重点对市面上主流的720*1280和1080*1920手机进行适配,同时对于其他类型手机也要适配。 关于屏幕适配,之前写过一个Android屏幕完美适配方案 ,点击前往,这里不再重复表述。 5、程序架构MVP 上图介绍: Contract: 契约类,一个功能模块中View接口、Model接口和请求数据回调统一在对应模块的Contract中定义,便于管理。ViewInterface: view层接口,定义了view中的UI操作ModelInterface: model层接口,定义了model负责的数据操作方法,如请求接口,操作数据库等CallbackInterface: model层操作数据完成后的回调BasePersenter: Persenter父类,主要是对相关view的获取,销毁等操作View: view层实现类,主要就是Activity或Fragment,负责UI展示和事件响应Model: model层实现类,就是依据业务,请求对应接口或数据库,并将结果返给回调CallBackPersenter: persenter层类,负责业务逻辑处理,view将响应传给persenter,persenter负责调用model,并将结果返回给view供其展示MVP: MVP模式相当于在MVC模式中又加了一个Presenter用于处理模型和逻辑,将View和Model完全独立开,在android开发中的体现就是activity仅用于显示界面和交互,activity不参与模型结构和逻辑。 使用MVP模式会使得代码多出一些接口但是使得代码逻辑更加清晰,尤其是在处理复杂界面和逻辑时,我们可以对同一个activity将每一个业务都抽离成一个Presenter,这样代码既清晰逻辑明确又方便我们扩展。当然如果我们的业务逻辑本身就比较简单的话使用MVP模式就显得,没那么必要。所以我们不需要为了用它而用它,具体的还是要要业务需要 现在比较流行MVVM架构,后续我会将MVVM总结,大家期待一下。。 6、package划分 如上:主体按功能模块划分,同一级的还有一些技术点,如adapter、util、pay等;在功能模块下,按照mvp模式,又分为contract、model、presenter、fragment和activity;而在其他技术点包下面同样也按功能模块划分。 总之,我们划分包时:以功能模块为主,以技术点为辅 。 希望能对大家有用 7、Base、Util、UI类封装 A、Base类 BaseApplication BaseActivity BaseFragment BasePresenter 等
a、BaseApplication :
主要进行一些例如:三方配置 、热更新加载 、文件配置 、数据库配置 等准备工作;同时也许定义全局性变量:如Application的Context 、网络状态 、主线程Looper 、主线程Handler 等。
b、BaseActivity :
封装为抽象类,将各任务抽取成方法,有子类实现:比如findViewById(initView) 、initData 、setListener 等;
对友盟统计的封装:因为友盟统计或别的统计需要在所有Activity的各生命周期方法中调用api,所以应该将其封装到BaseActivity中。
项目为MVP结构,所以设置了View和Presenter的泛型,如:
其中定义了屏幕宽高度等设备信息,也定义了BasePresenter对象、并抽取抽象方法,由子类返回其对应presenter。
c、BaseFragment :
BaseFragment的封装如BaseActivity一样,添加View和Presenter的泛型和presenter对象,创建返回Presenter的抽象方法供子类事项;
创建createView (创建跟视图view)、initChildView (子view findViewById)、initData (加载数据)抽象方法
d、BasePresenter :
BasePresenter封装如上:内置view的软引用,在Activity或Fragment的onResume中调用presenter的attachView方法,将view实例传给presenter;在Activity或Fragment的onDestroy或onStop方法中调用detachView方法解除与view的绑定;而getView方法则是presenter在model返回数据后调用来操作对应view的展示UI方法。
B、Utils类 只列举一些常用的工具类: SharedPreferenceUtils ToastUtils StorageUtils FileUtils NetUtils deviceUtils DateUtils LogUtils AppUtils 等 C、UI类 只列举一些常用的View类 下拉刷新、上拉加载 圆形ImageView 自定义Dialog Banner 自定义ScrollView 自定义RecyclerView 项目相关的自定义View 等 8、数据库 关于数据库操作,之前一直是自己写:也就是SQLiteOpenHelper结合相关SQL操作工具类来实现数据库操作。 但随着业务逻辑的增加和复杂,需要进行大量的数据库操作时,编写大量的代码,既费时间、还会避免不了地出bug; 所以我们只介绍几款流行的数据库框架: GreenDao OrmLite LitePal Realm GreenDao: 特点:1.存取速度快; 2.支持数据库加密; 3.轻量级; 4.激活实体; 5.支持缓存; 6.代码自动生成 地址:https://github.com/greenrobot/greenDAO OrmLite: 优点: 1.轻量级;2.使用简单,易上手;3.封装完善;4.文档全面。缺点:1.基于反射,效率较低(本人还没有觉得效率低);2.缺少中文翻译文档 jar包地址:http://ormlite.com/releases/ LitePal: LitePal 框架是郭大神开源的数据库框架,他的博客也比较详细的介绍了其用法。 地址:https://github.com/LitePalFramework/LitePal Realm: 1.易用:Ream 不是在SQLite基础上的ORM,它有自己的数据查询引擎。并且十分容易使用。 2.快速:由于它是完全重新开始开发的数据库实现,所以它比任何的ORM速度都快很多,甚至比SLite速度都要快。 3.跨平台:Realm 支持 iOS & OS X (Objective‑C & Swift) & Android。我们可以在这些平台上共享Realm数据库文件,并且上层逻辑可以不用任何改动的情况下实现移植。 4.高级:Ream支持加密,格式化查询,易于移植,支持JSON,流式api,数据变更通知等高级特性 5.可视化 git地址:https://github.com/realm/realm-java 官网:https://realm.io/docs/java/latest/#getting-started 自己项目中使用了GreenDao,它代码自动生成、存取速度快、支持加密、一个轻量级别的库,用着方便,推荐大家使用GreenDao。 9、图片处理 之前有自己封装过图片处理框架,核心是使用HttpUrlConnection实现加载,仿LruCache(近期最少使用排序)算法实现图片缓存。 但我们用的最多的还是ImageLoader、Glide、Picasso和Fresco四大主流框架,接下来主要比较一下四个框架的各自特点: ImageLoader: 优点: 多线程下载,线程管理。 多级缓存架构设计和策略,内存缓存,磁盘缓存,缓存有效性处理。 图片压缩,特效处理,动画处理。 复杂网络情况下下载图片策略,例如弱网络等。 内存管理,lru 算法、对象引用、GC回收等优化。 缺点: Glide: 优点: 更易用,因为Glide的with方法不光接受Context,还接受Activity 和 Fragment,Context会自动的从他们获取。同时将Activity/Fragment作为with()参数的好处是:图片加载会和Activity/Fragment的生命周期保持一致,比如Paused状态在暂停加载,在Resumed的时候又自动重新加载。所以我建议传参的时候传递Activity 和 Fragment给Glide,而不是Context 。 Glide可以加载GIF动态图。 Glide缓存的是跟ImageView尺寸相同的。Glide的这种方式优点是加载显示非常快。 默认使用HttpUrlConnection下载图片,可以配置为OkHttp或者Volley下载,也可以自定义下载方式。 默认使用手机内置存储进行磁盘缓存,可以配置为外部存储,可以配置缓存大小,图片池大小。 默认使用两个线程池来分别执行读取缓存和下载任务,都可以自定义。 缺点: Glide加载的图片质量要差于Picasso,这是因为Glide默认的Bitmap格式是RGB_565,比ARGB_8888格式的内存开销要小一半。 Picasso: 特点: 在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题。 使用复杂的图片压缩转换来尽可能的减少内存消耗 自带内存和硬盘二级缓存功能 Fresco: 优点: 最大的优势便在于5.0以下(最低2.3) bitmap的加载,在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem),而且图片不显示时,占用的内存会自动被释放,这会使APP更加流畅,减少因图片内存占用而引发的OOM。5.0以后的系统默认存储在Ashmem区了 图片的渐进式呈现,图片先呈现大致的轮廓,然后随着图片下载的继续,逐渐成仙清晰的图片,这对于慢网络对说,用户体验更好。 支持加载Git动态图和Webp格式的图片。 缺点: 总结:在项目开发中,要适当的选择图片框架,ImageLoader太老已过时,且官方不再维护,所以不再考虑使用ImageLoader;Picasso能做的,Glide都能做到,就是Glide的图片质量会稍差一些;而Fresco又体积偏大,但渐进式呈现,用户体验好。综上的话,一般项目建议使用Glide即可。 10、网络框架 上一个项目中,网络框架自己封装:核心使用HttpUrlConnection实现,先封装请求参数相关类RequestVo,其中包含请求方式 、url 、参数 、解析类 、是否缓存 、缓存时长 等参数;缓存是将json字符串加密后与拼接过的url成对存储到File,并且设置有效时间,超过有效时间删除缓存并去网络请求,成功后重新保存。 但现在市面上最流行的是Retrofit+RxJava+Gson,接下来我们大概介绍一下: a、添加依赖 要注意:以上添加了Retrofit、RxJava和Gson依赖,版本号必须一致 b、登录Service login方法的返回值是Observable类型,就是RxJava中的被观察者。 c、网络请求 RxJava + Retrofit 形式的时候,Retrofit 把请求封装进 Observable ,在请求结束后调用 onNext() 或在请求失败后调用 onError()。 可以看到,调用了service的login方法后得到Observable对象,在新的线程中执行网络请求,请求成功后切换到io线程执行保存用户信息的动作,最后再切换到主线程执行请求失败onError()、请求成功onNext()。整体的逻辑十分清晰都在一条链中,就算还有别的要求还可以往里面添加,丝毫不影响代码的简洁。 11、其他三方 在自己的开发过程中,还用到了如EventBus、Zxing、Zbar、Volley、Gson、LeakCanary等三方框架; 也用到了如友盟统计、微信、支付宝支付、三方登录、极光推送、tinker热更新等三方sdk; 就不再一一列举,附上一张图,大家有时间多去学习、多去了解。 12、混淆、加固、上线 混淆 大家可以参考我的另一篇文章http://blog.csdn.net/jiashuai94/article/details/77991077
混淆是上线前挺重要的一个环节。Android使用的ProGuard,可以起到压缩,混淆,预检,优化的作用。 坚持以下几项原则: 使用三方依赖,在混淆文件中添加官方提供的混淆代码,官方没有就google; 实体类不混淆,因为实体类涉及到与服务端的交互,各种gson的交互如此等等,是要保留的; 与js互调的类不混淆; 与反射有关的类不混淆 等。
具体语法: 加固: 加固一般都使用三方加固:如果apk上百度应用市场,则使用百度加固,其他情况建议使用360加固,当然,加固前一定是混淆过的、并且签过名的apk。 360加固还提供了一些其他服务,可根据项目情况操作(是需要花钱的..) 上线: 也就是我们所说的发版,当你的apk测试通过,混淆过、签名过、也加固了,可以发版了。 每个公司上线的市场要求不同,一般主要有应用宝、360、豌豆荚、百度市场、小米市场、华为市场、魅族市场等,当然还有官网了。 发版时需要:apk当然要有、logo(第一次上线)、应用简介(第一次上线)、版本号、更新功能、介绍图、官网地址(第一次上线)等。 ok,到这里,我们的一个阶段算是完成了,接下来还会有更多的业务和bug等着大家,哈哈!希望这篇文章能对大家有一点点帮助。 13、感谢 感谢天行数据的数据支持; 感谢各位博客大佬的支持; 因为时间、水平有限,文章中有不足或不对的地方,希望大家能够指出,我们一起进步。