快速开发一个新小项目①轻MVP架构-MVCP

标签: android 架构 轻mvp MVCP kotlin


先看代码吧0。0

①数据获取代码样例

model 层

class UserListRequest(
    page: String? = null,
    pageSize: Int? = null
) : ListRequestData<Void>(null, page, pageSize, USER,"getList")

presenter层

ApiRepo.post(UserListRequest()).subscribe()
//切换数据源
CacheRepo.get(UserListRequest()).subscribe()
DbRepo.get(UserListRequest()).subscribe()
SpRepo.getBean(UserListRequest()).subscribe()

以上就是调用一个接口所需要做的

  1. 创建请求类request
  2. 发送请求
  3. 创建响应类response(可选)
    不需要为每个具体请求添加额外的方法。

②基类、工具

以Http请求为例

model基类

//列表请求基类
open class ListRequestData<out T>(
    val condition: T? = null,//condition是具体查询条件
    val page: String? = null,
    val pageSize: Int? = null,
    module: String, //请求模块名,自动写入到请求地址中
    method: String //请求方法名,自动写入到请求地址中
) : RequestData(module, method)
//通用请求基类
open class RequestData(
    @Transient val module: String,
    @Transient val method: String
)

仓库repo

//封装成rx模式,将数据转换为BaseResponse,用户只需要传入request请求,就能得到response
object ApiRepo {
   fun post(request: RequestData, autoAsync: Boolean = true, needCache: Boolean = true): Observable<BaseResponse> {
    return HttpUtils.post(request)
                .compose<BaseResponse>(DealTransformer())
                .autoAsync(autoAsync)
    }
}

工具类HttpUtils

internal object HttpUtils{
    fun <T : RequestData> post(request: T): Observable<String> {
        return encryptRequest(request).flatMap {
            HttpManager.create(BaseApi::class.java)
                    .post(request.module, request.method, it)
        }
    }
}

retrofit统一接口

//使用retrofit2,非标准RESTFul协议,只保留post,
internal interface BaseApi {
    companion object {
        const val PREFIX = "api/"
        const val MODULE = "module"
        const val METHOD = "method"
    }

    @POST("$PREFIX{$MODULE}/{$METHOD}")
    fun post(
            @Path(MODULE) module: String,
            @Path(METHOD) method: String,
            @Body body: RequestBody
    ): Observable<String>
}

不管使用的是http请求、数据库、缓存或是其他数据源,我们都可以用统一的方式调用处理,同样的model,可以适用于http、lru、db、sp,从而实现,切换数据源而不需要做其他改动。
静态工具类代替多态,提升了性能,也减少了工作量。

补充
在这种方式下,一般的操作都已经适用。如果有特殊情况需要特别处理,那也就是另外一个XXXRepo的事。
如果你不想用通用的方式,而是按照模块划分Model,也是可以的
这时候就是我们常用的多态了,kotlin以委托的形式实现

interface IUserApi {
    fun getUser(request:UserListRequest)
}
class UserApi : IUserApi {
    override fun getUser(request:UserListRequest)=...
}
//不是省略,而是真的只有这么一行
class UserRepo(val api: IUserApi) : IUserApi by api
//调用方式
UserRepo(UserApi()).getUser(UserListRequest()).subscribe()

这种方式,明显比使用静态类麻烦了,如果有特殊需求可以考虑,但不建议使用。

下期预告

由于篇幅问题,这里只有数据请求的代码,还有界面相关的完整代码将会在下一篇出来。源代码会在整理好后放到github

后续计划

  1. 一般界面模板
  2. 列表界面模板
  3. 空界面、错误界面、加载中界面、自动分页
  4. BaseObserver、BeanObserver、ListObserver、ConvertListObserver、SimpleListObserver
  5. IListHelper、CacheListHelper、SimpleListHelper
  6. 快速开发,10秒完成界面代码框架
  7. 使用脚本自动生成通用代码

说一些废话0,0

1. 起因

在新项目来临时,手底下只有一个新手,而本人却在其他项目分身乏术的情况下,改进项目架构,成了避免日夜加班的唯一手段。

重复的劳动力操作,不仅会让程序员加班,还会让程序员产生消极心理,限制程序员的成长。浪费生命可耻啊!!所以,消除重复性劳动,才是我写这文章的最主要原动力。

2. 现状

对于现状Android流行的架构设计
简单的就是MVP,但是冗余代码太多,带来的可复用的好处却是很少见。
复杂的就是各种插件化,路由,解耦架构。但是这些架构,都是更加适用大型项目,不符合创业项目的开发速度要求。
于是乎,我需要一个可以快速开发的架构,在这个基础上,做一些基本的解耦,以方便日后项目架构升级。

3. 介绍

这是一个基于kotlin开发的轻MVP架构,开发者可以根据需求自由选择使用程度,而在需要增加层次的时候又不会有太大的改动。
基本原则是,只根据现有需求开发,不停维护迭代。

传统MVP

activity作为一个事件与生命周期的入口,作为view层不够纯粹。
同理,presenter直接隔离与activity之外,会导致冗余代码过多。
不要小看这么一两句代码,重复的劳动力操作,会让你怀疑人生!

轻MVP,不同于传统的MVP,

Model:Request、response、bean,通过Repo获取
View:新创建一个View层来控制界面显示(传统MVP把activity当成V)
control 事件入口,管理P、V,如:activity、adapter、helper...
presenter 对应于具体的界面的业务逻辑,在此使用Repo获取数据

activity 事件入口,属于control,简单的界面可以兼任presenter
viewHolder:视图句柄(kotlin有anko可以省略这个,但是目前技术尚未成熟,暂时用着先吧)
util 静态工具类,不涉及具体业务逻辑
manager 静态管理类,对于相同模块或业务逻辑的统一管理,如AppManager、UserManager、LoginManager、FooManager...
helper 辅助类,对某些特殊功能的管理,比如AnimHelper,属于control

4. 项目结构

完整MVP依赖关系图
完整MVP依赖关系图
简化MVP依赖关系图
简化MVP依赖关系图

a、app模块结构

项目架构1
项目架构1
common 项目相关工具类
entity VO、EventBus、常量表等实体
gm     全局管理,一个静态的工具类,方便对于相同模块或者业务功能做统一的处理
facade 具体业务、界面

以main为入口,home为首页,四个tab独立放一个包,其他的则另外按照模块分,这里由于app中有两个角色,所有有了aunt、customer两个区分,common则是共用的界面。

b、core模块结构

core模块结构
core模块结构
utils  工具类
base   简化操作的基类
module 具体模块的request、response、entity
repo   仓库,封装具体工具或者DAO的操作,这里将所有请求都封装成rx流操作模式

附:偶然一次发现,阿里有一个TheMVP的概念,在以activity作为presenter的想法是不谋而合,大有天下难得一知己的感慨。本文只讲述架构,如有侵权,请联系本人。

某个不要脸的居然要我在这里感谢他,那就,感谢不要脸大神ivy吧!

说了这么多废话,,下面进入正题

正题
正题
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容