最近在作一功能不大、业务也不复杂的小众App,以往作App是发现本身历来没有考虑过一些架构方面的问题,只是按照本身以往的习惯去写代码,忽略了App的设计。本次分享主要包含一些开发App的小经验和技巧,来一次App开发与设计的分享。前端
先和分享下一下实体类的设计与组织形式java
在作App开发的时候有不少的实体类,项目越复杂实体类就会越多,通过个人一番思考大体这能够将实体分为如下几大数:数据库
通常状况下实体类的操做会通过如下步骤:编程
如今的实体的产生只用在请求服务器数据的时候才须要新建,后续的数据库、页面渲染实际上是可使用一套实体:json
先不说这样作的行不行,首先三个地方使用同一实体就会引发字段歧义好比服务器数据有Id、本地数据也有Id,那两个id字段就有冲突了不起不改字段名。后端
另外一种状况渲染和数据自己并不会一一对应,有时候后端数据给的是一个纯数字而前端页面显示的是字符串两个都对应不上,强行放在一块儿会起来更多的问题。服务器
所为实体类的的正确组织形式应该是:相互隔离、互不干扰:微信
数据实体的在渲染以前都须要准备好,好比在ViewModel中将int型的数据转换成文本型的数据而后再使用Databinding+页面渲染实体来渲染页面。网络
如今Android开发使用的网络库大部分都是Okhttp + Retrofit
,使用Retrofit网络交互变的很是简单一个Service接口就能搞定一切,美兹兹~~,如今大部分后端返回的数据都会是如下形式:架构
{ "code":0, "data": {}, "msg": "" }
虽然不能涵盖全部,但仍是能够很是赞的数据、消息、成功与否啥都有!对于前面主要是关注data
字段,其余msg
、code
等都属于辅助字段。前端对应的实体对象应该是这样的(假代码):
public class ApiResponse<T> { private int code; private T data; private String msg; }
对应的Service那就得定义成这样(使用了RxJava):
public intface UserService { @GET("/xx/{id}") Single<ApiResponse<UserInfo> getUserInfoById(@Path("id") Long userId); }
从接口中能够看出来,方法的返回值就包了几层,若是要拿data
字段须要通过:ApiResponse -> UserInfo
,并且在拿以前还要判断code
字段:
... if(ApiResponse.code == 0){ UserInfo info = ApiResponse.getData(); } ...
为了消除这些冗余的代码可使用CallAdapter
来使Service方法返回的数据直接就是实体类:
public intface UserService { @GET("/xx/{id}") Single<UserInfo> getUserInfoById(@Path("id") Long userId); }
CallAdapter
的代码就不贴了,能够自行查找。这样作带来的另一个问题就是业务代码如何判断接口是否成功或失败,前端必需友好的把错误提示给用户而不是一直搞个Loading在那里瞎转~~。现阶段最方便的的错误传递方式是使用Java异常,前端能够定义业务异常或网络异常:
public class BizException extends RuntimeException { ... }
在CallAdapter
中检查ApiResponse的返回值是否成功:
if(!ApiResponse != 0){ throw new BizExcepiton(ApiResponse); }
若是后端返回业务异常那前端就对应抛出一个BizExcepiton
,若是是http错误如:40四、400那能够抛出HttpException
。除了BizExcepiton
和HttpException
外还可以使用特定的异常好比后端返回密码错误异常:
public class InvalidPasswordException extends BizException { ... }
如需特殊处理,也能够知足要求。
如今不少应用都开发使用MVVM开发模式数据层都使用Repository
来表示,面向数据驱动的开发模式,页面变化都须要随着数据变动而更新,数据发生变化而后页面再作出响应。Repository的拆分要细一点,不建议简单的弄个UserRepository
包含登录、注册、更新密码等等操做,设计Repository
的一些想法:
一个判断是不是好的设计的办法能够这样:一个登录页面从Activive/Fragment到ViewModel再到Repository,有没有多余的代码。好比上面说的UserRepository
包含登录、注册可是在一个登录页面就不须要有注册功能,从登录页面上来看注册的代码就是多余的(有些App登录/注册在一个页面的~~)。
一个包含登录、注册的UserRepository
简单图:
另一点是尽可能将repository使用到的一些东西集中管理,可引入一个基础的repository:
public class SimpleRepository { protected final <T> T getService(Class<T> clz){ return Services.getService(clz); } }
作为SimpleRepository
的子类,就不须要考虑从哪里获取service的问题。
UI层面能够分为ViewModel和View(Activity/Fragment), View的职责应当只有二点:
例如一些数据的组织、判断都不该该出如今View中好比:
if (Strings.isNullOrEmpty(phone)) { ... return; } if (Strings.isNullOrEmpty(pwd)) { ... return; }
像上面这类的代码都不该该出如今View中,而在放置在ViewModel里面,View只收集用户数据传递给ViewModel由它来进行数据校验。再好比像这样的if/else代码也应该放置在ViewModel中:
int age = 10; String desc = ""; if(age < 18){ desc = "青年"; }else if(age < 29){ desc = "中年"; }
若是数据的显示和数据的收集过多,建议使用Databinding来进行双向绑定数据。再搭配LiveData
使View做为观察者实时监听数据变化:
registerViewModel.getRegistryResult().observe(this, new SimpleObserver<RegistryInfo>(this));
一旦数据发生变化LiveData
就会通知Observer更新,经过DataBinding更新各个页面数据。
再说ViewModel应该只包含一些简单的判断、检查、打通数据的代码,若是业务过于复杂能够考虑加Presetner,若是真的超级复杂那能够反思下这个复杂的逻辑应不该该放在前端,能不能放在后端呢?
<br> <br>
欢迎关注微信公众号《架构文摘》,高质量技术文章第一时间推送。