Skip to content

Latest commit

 

History

History
108 lines (67 loc) · 8.71 KB

README.md

File metadata and controls

108 lines (67 loc) · 8.71 KB

CCTrainer

CC老司机 邀你上车一起耍 (仅供参考)

目的:尽可能帮助更多改造原有项目和新手接入CC,产生的各种困惑

  1. 接入成本是否高
  2. 接入后网络框架是否可抽离
  3. 接入后消息传递是否可解耦
  4. 接入后三方库怎么做到抽离、共用
  5. 接入后杂乱的资源是否可分割
  6. 接入后是否会增加编译耗时

一、接入成本不高

CC的文档也是极尽详细,大家按着文档里的步骤一步一步来就行了。

  • 这里我的一个建议是,提前把自己的业务模块划分好,确定哪几个是需要分离,哪些是不确定的。需要分离的moudle可以直接接入CC,不确定的也是可以先放着不动,而不像其他的组件化方案一样,需要对项目整体进行路由改造,这就是billy大佬强调的可渐进式改造。

二、网络框架可抽离

现在主流的网络框架是rxjava+retrofit+okhttp,同时结合mvp模式,可以在界面里把一个网络请求做到极简化。组件化后,网络框架该怎么处理呢?怎么避免接口实现类里动辄上百个接口和一堆分不清是否重复的数据类?怎么优雅避免网络请求带来的内存泄漏问题?下面就探讨下这些问题。(具体详细用例请看CCTrainer项目)

  • 每个组件都要使用网络框架请求数据,请求的主体是不变的,而每一个请求的接口实现和返回数据是不同的,那我们就把网络框架骨干下沉到公共库里,接口实现会在各模块独自创建,当然数据类也会写在各自模块内,这样就避免了网络框架的接口和数据类的混乱。至于怎么写,大家可以参考下CCTrainer里的实现方式,把网络框架下沉到demo_common_base公共库里,里面封装retrofit请求单例Http,和泛型静态方法getApiService,通过这个泛型方法传入不同模块的请求接口类,实现各模块的接口类分离,对应的返回数据类也就在各自模块创建,再也不会混乱不堪。

    调用例子如下

     @Override
     public Observable<Response<User>> login(String code) {
    
         return Http.getApiService(LoginApiService.class).login(code)
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread());
         }
     }
    
     public static <T> T getApiService(Class<T> tClass) {
             return getRetrofit().create(tClass);
     }
    
  • 网络请求的内存泄漏问题,处理起来也很麻烦,记得以前最开始的时候需要引入rxlifecycler库,然后要把基类继承的activityfragment类替换成rxactivityrxfragment,在每个请求处理上加上.compose(this.bindUntilEvent(ActivityEvent.XXX)),这样处理起来并不是很赞。在CCTrainer里,会让你感觉不到处理的存在。CCTrainer里封装了一整套的mvp模式,mvp模式实现网络请求处理和返回数据的刷新操作,大家应该都很熟悉。通过泛型,在每个界面指定presentermodel和实现view接口。而网络请求里通过订阅观察者把接口返回的数据刷新到界面上,我们可以自定义一个观察者类,在类里通过抽象方法getDisposable向子类暴露当前订阅事件disposable,然后在presenter类里通过basepresenter里的rxmanager类持有当前订阅事件disposable,而rxmanager类是在basepresenter里初始化,并在onDestroy方法里取消全部的订阅事件,避免内存泄漏。

     public void onDestroy() {
         Log.e("presenter", mContext + "-->>" + mRxManager);
         mRxManager.clear();
     }
    

    onDestroy在什么时候调用呢?答案肯定是在baseactivityonDestroy里通过mPresenter去调用。

     @Override
     	protected void onDestroy() {
     	super.onDestroy();
    
     	if (mPresenter != null) {
     	    mPresenter.onDestroy();
     }
     
    

    这样等于在调用网络请求的同时,把订阅事件都给管理起来,在界面销毁的时候去取消这些订阅事件。

三、消息传递可解耦

事件总线大家一般都采用的eventbus,具体使用就不多说。需要传递消息的时候,创建一个事件类去发送。集成CC后,不同模块间也可以用eventbus那样去发送消息,CC是支持的。但是在A模块创建的事件类,发送到B模块去接收,那B模块也需要有这个事件类。那怎么办,一般大家都会下沉到公共库里,这样所有模块都可以使用这个事件类。项目越来越大模块越来越多的时候,公共库的事件包里就会越来越臃肿,重复的事件和已弃用的事件相当不好维护。同时也违背了路由的基本原则,业务模块之间是隔离的。CC的路由方案精妙在于组件总线方案,引用billy的话

2.1 组件总线的本质是转发调用请求

其工作原理类似于电话接线员(中介者模式):组件总线负责收集所有组件类并形成映射表(Key为字符串,Value为组件类的对象)。调用组件时,总线根据字符串找到对应的组件类并将调用信息转发给该组件类,组件执行完成后再通过组件总线将结果返回给调用方

2.2 组件总线只负责通信,即转发调用请求和返回执行结果。

当A模块要发一个事件去B模块时,需要先找到B模块的组件类,把对应的要处理的事告诉B模块的组件类,然后就跟B模块没有任何关系了。B模块的组件类收到这个事件去查找自己是否有这样的一个事件处理,有就执行。大家会说这只是发消息事件发到B模块的组件类里,并没有发送到对应的类里,那我们再在B模块的组件类里去发送一个事件类去通知B模块里对应的类接收,这样就OK了。整个传递过程,A模块跟B模块没有产生任何关联,没有共用一个类,但是该做的事我们同样做到了。同时这样可以把消息事件类给隔离开,每个模块下都有属于自己的事件类,再也不怕事件类太多,看着头皮发麻了。

四、三方库的抽离

三方库的依赖都在公共库的gradle里,极光推送接收放在消息模块下,大家可以把自己的极光key配置到JPUSH_APP_KEY里,接收消息后需要跳转到其他模块,跟消息传递一样处理。

CCTrainer集成几个通用的三方库,BUGLY、JPUSH等,如果你用的哪个比较不好划分可以告诉我。

五、资源文件的划分

这个是最耗时的操作,当初接入CC的时候,花了我一个周末的时间把各种资源给拆分开,归置到对应的模块下。其实没什么说的,主要看公司的设计UI,好多资源文件需要共用,drawable里的shape文件,strings里的字符串,colors里的颜色等,大部分要下沉到公共库里去,拆分的时候本来想着只有一个模块用,后来发现其他模块也需要,所以能下沉就下沉到公共库,这个也是没办法,毕竟UI配色方案什么的都是一套。至于图片是最不好处理的,但是图片资源也是需要拆分下,如果图标只有一个模块用那就归置到对应模块下。
等你归置完后,再去看各个模块下得资源文件,就清爽很多。这只是我个人的做法,仅供参考。

六、编译跟接入前没什么区别

项目变大之后,带来最直观的感受就是编译一次耗时比之前更慢了,依赖库越来越多,依赖的层级关系越来越复杂,A依赖B、C、D、E、F,BCDEF又依赖着公共库,公共库里又一堆三方库,公共库又依赖着网络库等等。这就是拖死项目编译时间鬼畜依赖。如果把项目的模块都打平,不再存在主壳app,所有的模块全是平级关系,而公共库只有一个为各模块提供公共依赖,那样,上面的关系将会变的简单多。
而CC就是这样的,CC把所有的模块拍平,不再存在主次关系,有的只是每个模块依赖一个公共库而已。

更新:

这里再跟大家说个小技巧,集成CC后,组件之间都是平级关系,大家在build variants里去切换环境的时候,各组件需要一个一个切换,每切一次都要等待很长时间的gradle sync,后来才发现,在右侧功能栏Gradle里,app->install下面,可以一步切换不同环境,另外,如果连着多台设备,也会同步安装,真的是省心省力。唯一的不足是安装后,是不会立马运行起来,需要手动打开。

在这里插入图片描述