RxJava+Realm+MVP+ARouter+Retrofit框架搭建

去年就一直想搭建一个框架,可惜一直拖到年初才有时间。熟话说基础不牢地洞山摇。当然我们要先看项目的组织结构,既然是一个通用的库,就只能包括通用的模块。
项目模块划分
|- base
|-BaseApplication
|-BaseActivity
|-BaseFragment
|-BaseActivityLifeCircleCallbak
|-db
|-message
|-network
|-okhttp
|-retrofit
|-HttpManager
|-utils
|-ARouter
|-monitor
这里我们对于模块的组合采用了Router方式,对于ios或者前端的人士应该比较熟悉,对模块复用解耦比较简单,大体项目结构如上,有些小的类就没写了,以及一些模块持续更新中。下面的讲解就以我的添加顺序来了

Network

网络模块在一个App中属于大模块,而且相对独立,所以我选择首先建立。这里选取了Retrofit+Okhttp3的插件,本身都是square出品的Retrofit与其说是为了OkHttp而生的也不过分,关于OkHttp的分析请参考我的另一篇OkHttp核心理解,关于Retrofit是基于主流请求都是restful风格,使用请参考Retrofit使用没什么大的东西,主要是对一些注解的理解。
这里可操作性比较大的就在与我们的OkHttp里面,他的精髓大概就是Interceptor了吧。
因为网络模块可以分为日志,缓存,Https,授权(废弃)。

  1. 日志模块我们往OkHttpClient里加了一个ApplicationInterceptor,获取request以及Response的信息,这里日志我用了自己上传Jcenter的项目,比Logger难看点,附上github地址BullDog
  2. 缓存这边情况比较复杂,大概讲下遇到的困难,后来就放弃了第一种方案,本来如果设计合理的话,我们其实可以使用Interceptor直接实现无网络使用缓存,有网络更新的策略。但是由于OkHttp的默认缓存是只支持Get的与我们的实际情况有所出入,反正我也讲下合理情况下的方案。
  • 首先我们需要了解下DiskLruCache,这个本来是一个开源项目,使用文件缓存,被google官方推荐,也被OkHttp内置了,区别就是OkHttp是用了Okio的流处理(Sink,SourceOkio使用,基本操作不难),需要了解DiskLruCache的请自行Google,由于本身的Api不太友好我进行了二次封装DiskLruCacheHelper

  • 先讲下设计合理的处理,本身我们的请求可以带Cache-Control这个头,在无网条件下只要我们在request内加入CacheControl.FORCE_CACHE这个参数,OkHttp内部会自行查询有无该缓存进行返回

  • 为什么说Get才需要缓存呢,其实我们缓存需要一个Key,如果是get的话我们直接可以把url作为key,但是如果是post其实我们区分key的是post body里面的信息,这样就比较难处理,比如一个人的信息,get的话是带uid这类标识符的,post的话我们就无法区分是哪个人的信息了。然后是解决方法,我这边的网络请求是加了一层壳的,我们知道Retrofit结合Okhttp返回的结果是Observable,所以我们在Subscriber里面做文章,在返回接过钱我们既可以捕捉异常,又可以加缓存,这边的请求我多了一个cacheKey的参数,可以自由配置我们需要缓存的信息。根据我们的策略我们先判断有无网,有网则更新缓存,无网则取出缓存返回。

  1. Retrofit模块,这个模块没什么好讲,主要是用于写请求的,以及一些基本配置
  2. 最后加了个BaseNetWorkCallbackBean用来规范我们的网络返回

总结,这边模块分的比较多,主要遵循组合大于继承,有利于以后的拆解阅读。

DB

Db模块以前我们用的大多是core data比如说greenDao,我用的这个realm在ios平台用的比较多,网上有关于这块区别的讲解,主要还是从效率上来讲,realm明显要高出core data这块很多,有点缺陷就是对bean的污染,每个bean都要继承RealmObject,照某网友的说法就是强奸代码。Realm官方网站
我这边主要是对Realm进行了简单的封装,对一些常用操作简单化,比方说insert,query,delete由于Realm不支持sql语句查询,所以自由度相对也就差点,不过移动端不像后端需要复杂查询各种外键条件的,我封装的几个查询应该已经满足日常使用了,此外Realm还支持异步,但有一点千万要注意,Realm的操作类并非单例,你获取一个,他就线索树里面多一个引用,所以每次使用完记得释放,这里我是在BaseActivity的生命周期内控制的,只不过异步的情况要复杂一点,在api封装上也是讲realm对象作为参数传入,在最后进行释放。

Base

这个是比较基础的部分,为什么不选择先建是因为有些东西是随着模块的加入逐步完善的,比方说前面提到的Realm,还有后面的RxBus。

  1. BaseApplication,这个类的核心在于一些插件的初始化。涉及到这个如果我们的插件比较多,势必影响到APP的启动速度,所以我们最简单的处理就是启用线程池,引入异步初始化,但是需要注意有些操作是一开始就需要的只能放在同步操作里,比方说Log框架的加载。这里我封装了一个ApplicationInitializer,主要的就是使用cacheThreadPool来控制初始化,分离的目的也是为了单一职责。以下为一些类的初始化
        BLog.init();
        /* 其他初始化任务无时序要求可多线程处理 */
        cachedThreadScheduler.execute(new Runnable() {
            @Override
            public void run() {
                Realm.init(application);
                RealmConfiguration realmConfiguration = new RealmConfiguration.Builder()
                        .name(DB_NAME)
                        .deleteRealmIfMigrationNeeded()
                        .build();
                Realm.setDefaultConfiguration(realmConfiguration);
            }
        });

        cachedThreadScheduler.execute(new Runnable() {
            @Override
            public void run() {
                Fresco.initialize(application);
            }
        });
        cachedThreadScheduler.execute(new Runnable() {
            @Override
            public void run() {
//                LeakCanary.install(application);
            }
        });
        cachedThreadScheduler.execute(new Runnable() {
            @Override
            public void run() {
//                BlockCanary.install(application,new AppBlockCanaryContext()).start();
            }
        });
        cachedThreadScheduler.execute(new Runnable() {
            @Override
            public void run() {
                ARouter.init(application);
            }
        });

除了初始化这块,ICE_CREAM_SANDWICH以后我们可以通过在Application内注册ActivityLifeCircleCallbak监听activity的生命周期,后面可以了解到Arouter也可以检测到,或者第三种方案就是在Application内维持一个List<Activity> activities,BaseActivity生命周期内去更新这个变量。

  1. BaseActivity 这个作为跨页面控制比较重要的结构,可以封装一些比较常用的方法,这里我主要维护了一个List<Fragment> fragments,用来管理activity下面的fragment,因为当前app主流还是单activity多fragment的模式,还有就是保存一些经常使用的变量,比如Realm,Rxbus还有ioc框架的初始化,这里的ioc我也是自己写的 比较简单,只有click,longclick两个事件Potato
Utils

这个模块就大概讲解下,主要都是一些基本的工具包,各个项目通用,github有提供下载。

Rxbus

类似与EventBus,因为本身我们引入了RxJava,所以用rxjava来实现事件总线是更可取的方法。参考rxbus实现,在post中采用了tag,更符合eventbus的使用习惯,具体就是封装Event包裹了一个tag对用户透明,在返回的时候先filter筛选然后采用flatMap进行转化

MVP

关于mvp模式的实现,中间想了蛮久,主要是纠结于怎样使用范型,在BaseActivity进行P跟V的绑定,以及P跟M的关联,参照了google的mvp实现,使用了contracts使接口或者抽象类更加关系明确,集中。
这里我们实现了BasePresenter<T>这里的T是用来引入M的,而V的引入在BaseActivity<V extends BasePresenter>这样就形成了一个V初试化P,然后P初始化M的链,P就成为了关键,当V destroy的时候就P就解绑V,释放M,把业务逻辑放到P上,插句题外话,中间了解了下mvvm也就是m-vm-v的模式,直接在布局层就将数据跟v通过viewmodel紧密结合了,省掉了findViewById的工作,但个人不太喜欢这种模式,感觉可读性较差,分层不是那么明确

monitor

监视框架,已经引入了blockcanary,leakcanary,接下来要引入aop设计进行关键点检测,然后接入友萌,这个就是中国版的firebase当初去外企面试被问倒了,哈哈哈

test

测试框架还没开始,主要分单元测试,espresso ui测试,mock数据...测试框架蛮多的,最近再看,按顺序来吧

ARouter

路由机制,github上有两个下载量多的,之所一选择ali的完全是信仰吧,基本就是一些配置,使用说明官网有ARouter,采用这种机制也是偶然在android weekly上看到人家一个老司机用这种框架搭建中小型项目,也算是一种新的尝试吧。

2017/3/1:更新Mvp

文章未完待续,尽量月底前完成接下来的工程,欢迎喜欢这文章的朋友下载我的代码,帮我发现问题,完善框架SpaghettiFrame

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

推荐阅读更多精彩内容