当前位置: 首页 > >

打造Android轻量级框架XSnow

发布时间:












今日科技快讯











昨日,京东正式宣布与奇虎360达成全面战略合作,共同启动“京奇计划”。双方将数据打通,京东的2.583亿高价值活跃电商用户的数据加上360覆盖线上线下的全场景用户行为链大数据,能够为京东*台上的商家实现更精准的广告投放;同时,京东将京东号的内容输出到360众媒*台,在360手机卫士App、360浏览器、360手机助手等渠道里通过智能分发的内容营销方式,提升京东号作者的内容变现能力。












作者简介











明天就是周末啦,提前祝大家周末愉快!


本篇是?幻影宇寰 的第二篇投稿,分享了自己的一个开源框架。文中除了对作者的开源库讲解,还推荐了一些主流开源库的分析文章,希望对大家有所帮助!


幻影宇寰 的博客地址:



https://juejin.im/user/5863647c61ff4b0063143dc0













前言











由于有使用的朋友提到?XSnow?框架信息量有点大,希望能有篇文章详细介绍框架中每个模块的细节,所以本文会围绕该框架将每一个模块的相关构思和重要技术点做一个详细的剖析,让使用该框架的朋友对?XSnow?有一个清晰的认识。













准备











由于?XSnow?框架是基于?RxJava2?和?Retrofit2?打造的,其中也依赖了如网络基础库?OkHttp、图片加载库?Glide?、数据库基础库?GreenDao?,所以使用该项目的朋友需要对这几个基础框架有基本的认识,下面将对这几个框架做一个简单的说明。


RxJava

熟悉的朋友可能知道该框架是属于?ReactiveX?编程库的一员,这是一种新的编程思想,一般都把它叫做响应式编程思想,对于使用该思想的优势在这里就不赘述了,感兴趣的朋友可以看看这篇文章



ReactiveX 文档中文翻译


https://mcxiaoke.gitbooks.io/rxdocs/content/Intro.html



RxJava?主要的模式就是观察者模式,何为观察者模式,可以简单的理解为:两个对象观察者与被观察者,其中观察者与被观察者建立了订阅关系,如果被观察者发生了变化那么需要及时通知观察者,观察者收到通知后做出相应的处理。描述可能会有点绕,举个通俗易懂的例子吧,比如说:顾客去买蛋糕这样一个场景(把顾客和蛋糕店店员分别看做观察者与被观察者),由于蛋糕是现做需要一定时间才能完成,顾客在购买时一般会先付钱给店员拿到一个付款凭证后离开去忙其他事,这样他们就建立了购买关系(建立订阅关系),店员在做完蛋糕后(被观察者发生变化),店员就会通知顾客来拿(消息通知到观察者),顾客在收到店员通知后前来拿蛋糕(观察者收到通知后做出相应的处理)。到这里,一个完整的观察者模式场景就讲解完毕,希望能帮助朋友们加深对观察者模式的理解。


下面继续讲解对?RxJava?的理解,先想象一个这样的场景,有一台万能机器,它可以生产任何东西,它有一个输入端、一个输出端,中间有很多核心组件,比如说转换器、转移器等,它们对外部都是隐藏的,但是外部有一个控制终端,可以输入任何想要的规则,机器就会根据规则,将输入端的东西通过终端制定的规则输送到输出端。RxJava?就是这样一台万能机器,它拥有数据输入端、数据输出端,中间也有很多可以操控数据的规则,比如说各种操作符、线程转换,它们都有一个目的,就是如何让数据源通过一定规则进行输出。


以上的讲解只是为了让你对?RxJava?有一个清晰的认识,不牵扯具体的技术细节,如果想详细了解的可以去看看



给初学者的 RxJava2.0 教程


http://www.jianshu.com/p/464fa025229e



这是一个系列,看完这些文章,基本就可以使用?RxJava?做一些基础的功能了,这个系列是针对?RxJava2?的,如果想了解?RxJava?第一版,想看看两个版本到底发生了什么改变,那么可以看看



给 Android 开发者的 RxJava 详解


http://gank.io/post/560e15be2dca930e00da1083




RxJava2 vs RxJava1


http://www.jianshu.com/p/850af4f09b61



Retrofit

Retrofit?简单来说就是一个基于?OkHttp?的?RESTful API?请求工具。RESTful?是一种架构风格,它的特点是资源、统一接口、URI?和无状态,如果想更详细的了解?RESTful?可以看看



RESTful 架构风格概述


https://blog.igevin.info/posts/restful-architecture-in-general



Retrofit?在使用时其实就充当了一个适配器(Adapter)的角色,主要是将一个?Java?接口翻译成一个?HTTP?请求对象,然后用?OkHttp?去发送这个请求。其中核心思想就是动态代理机制,什么是动态代理,就是当你要调用某个?Class?的方法前或后,插入你想要执行的代码。通俗来讲,就是你要执行某个操作的前后需要增加一些操作,比如查看用户个人信息前需要判断用户是否登录,用户访问数据库后想清除用户的访问记录等操作。


Retrofit?的设计非常插件化且轻量级,高内聚且低耦合。Retrofit?主要定义了 4 个接口:


    Callback:请求数据的返回;

    Converter:对返回数据进行解析,一般用?GSON?;

    Call:发送请求,Retrofit?默认的实现是?OkHttpCall,也可以依需自定义?Call

    CallAdapter:将?Call?对象转换成其他对象,如转换成支持?RxJava?的?Observable对象。


    Retrofit?进行网络请求的过程:


      通过?Retrofit?对象和?Method?对象获取?callAdapter、responseType?以及?responseConverter?三个对象;

      通过解析?Method?中的注解以及进行一系列的检查得到中心管理对象?ServiceMethod;

      通过?ServiceMethod?对象获取实际执行的?Call?对象执行?Http?请求。


      以上讲解只是对?Retrofit?的核心功能做了相关的解释,如果想更详细的了解?Retrofit?可以看看:



      拆轮子系列:拆 Retrofit


      https://blog.piasy.com/2016/06/25/Understand-Retrofit



      OkHttp

      OkHttp?是一个高效的?HTTP?库,它的总体设计图如下(图片来源:泡在网上的日子):



      OkHttp?的请求由?OkHttpClient?统一管理,采用的是门面模式,OkHttpClient?拥有子模块的所有配置和参数,并将请求分发到相应的子系统。它由以下几个核心子系统组成:路由、连接协议、拦*鳌⒋怼踩匀现ぁ⒘映匾约巴缡逝洹V饕峭ü?Dispatcher?不断从?RequestQueue?中取出请求(Call),根据是否已缓存调用?Cache?或?Network?这两类数据来获取某个接口,再从内存缓存或是服务器取得请求的数据。该引擎有同步和异步请求,同步请求通过Call.execute()直接返回当前的?Response,而异步请求会把当前的请求(AsyncCall)Call.enqueue?添加到请求队列中,并通过回调(Callback)的方式来获取最后结果。


      OkHttp?中的?Interceptor(拦*鳎┓绞蕉杂谡宓纳杓铺峁┝撕艽蟮陌镏捎玫氖窃鹑瘟茨J剑恢皇歉涸鹄菇厍肭蠼幸恍┒钔獾拇恚ɡ缭黾忧肭笸罚导噬纤咽导实耐缜肭蟆⒒捍妗⑼该餮顾醯裙δ芏纪骋涣似鹄矗恳桓龉δ芏贾皇且桓?Interceptor,它们再连接成一个?Interceptor.Chain,环环相扣,最终圆满完成一次网络请求。


      以上讲解只是对?OkHttp?的流程做了相关的解释,如果想更详细的了解?OkHttp?可以看看



      拆轮子系列:拆 OkHttp


      https://blog.piasy.com/2016/07/11/Understand-OkHttp



      Glide

      Glide?是为图片加载而生,一行代码Glide.with(this).load(url).into(imageView);就搞定图片的加载。使用非常简单,如果想详细了解的,这里推荐郭霖的 Glide 源码解析



      Android 图片加载框架最全解析


      http://blog.csdn.net/guolin_blog/article/details/53759439



      这是一个系列,看完后对于 Glide 基本就能知道怎么用和为啥要这样用了。


      GreenDao

      GreenDao?是一个将对象映射到?SQLite?数据库中的轻量且快速的?ORM?解决方案。如果想更详细的了解?GreenDao?可以看看



      Android 数据存储之 GreenDao 3.0 详解


      http://www.cnblogs.com/whoislcj/p/5651396.html



      以上对于基础库的讲解只是做了简单的介绍,让你对?XSnow?框架利用的相关技术有个直观的感受,如果想详细了解的,上面在每个基础库后面都备注了个人认为比较好的文章,可以当做学*该框架的参考。

      以下介绍都以包名作为每个模块的标题,这样也表明模块之间充分解耦,也方便读者对照代码进行理解,分析起来逻辑更清晰。













      Http











      网络模块,包含网络请求,上传下载。该模块是?XSnow?框架的核心功能,其核心思想就是将请求分离和基于动态配置,采用门面模式,上层不用关系具体实现细节,只需要简单配置相关的请求信息就可以达到完整的网络请求功能。该模块相对于其他模块代码量比较大,下面将会对该模块下的每一个包进行详细拆分讲解,现在我们首先来看看?ViseHttp?类,该类相当于该模块的门面类,也是网络请求的唯一入口类,所有的请求都是由该类构建,如:

        BASE:传入自定义请求对象,方便外部根据自己的需求自定义请求;

        GET:获取?GET?方式请求对象;

        POST:获取?POST?方式请求对象;

        HEAD:获取?HEAD?方式请求对象;

        PUT:获取?PUT?方式请求对象;

        PATCH:获取?PATCH?方式请求对象;

        OPTIONS:获取?OPTIONS?方式请求对象;

        DELETE:获取?DELETE?方式请求对象;

        UPLOAD:获取上传文件请求对象,支持传入上传回调;

        DOWNLOAD:获取下载文件请求对象。


        该类还提供了根据?tag?中断单个网络请求以及中断所有网络请求功能,也提供了根据?key删除缓存和清除所有网络缓存功能。必须注意的是,在应用初始化时必须调用该类的初始化方法:


        ViseHttp.init(this);

        以及相关的网络配置



        这样才能在应用中调用相关的网络请求功能。如果没有初始化,在调用网络请求时该模块会抛出如下异常信息:


        Please call ViseHttp.init(this) in Application to initialize!

        下面来分别讲解该模块下每个包的功能:


          api


          该包提供的是请求的?API,目前只有一个类?ApiService,主要提供的是?Retrofit?进行网络请求的请求方法。


            body


            该包提供的是相关的请求和响应?body,目前只有一个上传进度展示的请求实体类?UploadProgressRequestBody,通过传入?UCallback?来处理上传文件的进度回调。


              callback


              该包提供的是相关的回调类,目前包含上传回调?UCallback?和请求?API?回调?ACallback。


                config


                该包提供的是配置相关类,目前只有请求全局配置类?HttpGlobalConfig,该类提供了很丰富的配置方法,提供该类的目的是想将配置与请求分离。


                  core


                  该包提供的是一些核心功能类,目前包含缓存处理类?ApiCache、Cookie?管理类?ApiCookie?以及网络请求订阅管理类?ApiManager。缓存采用磁盘缓存方式,支持定制各种缓存策略,策略将在?strategy?包下进行讲解。Cookie?采用?SharedPreferences?存储,存储对象以十六进*斜4妗


                    exception


                    该包提供网络请求相关异常类,目前提供了请求异常统一处理类?ApiException,可用来判定请求失败的原因。


                      func


                      该包提供一些数据转换类,目前提供了由?ResponseBody?对象转?T?的?ApiFunc?类以及由?Observable?转?Observable?的?ApiRetryFunc?类。ApiRetryFunc类主要用来处理网络超时重试机制,可传入重试次数和重试间隔时间,这些都可以在配置类中进行配置。


                        interceptor


                        该包提供的是一系列的拦*骼啵飧霭菜闶歉媚?榈暮诵陌敬蟛糠止δ芏伎梢圆捎美菇*鞯姆绞嚼刺峁壳案冒旅姘缦吕菇*鳎


                        1、GzipRequestInterceptor:包含Gzip压缩的请求拦截;


                        2、HeadersInterceptor:请求头拦截;


                        3、HttpLogInterceptor:Http日志打印拦截;


                        4、NoCacheInterceptor:无缓存拦截;


                        5、OfflineCacheInterceptor:离线缓存拦截;


                        6、OnlineCacheInterceptor:在线缓存拦截;


                        7、UploadProgressInterceptor:上传文件进度展示拦截。


                          mode


                          该包提供的是相关的实体类。


                            request


                            该包提供的是所有请求相关的类,所有的网络请求都需要创建一个请求对象,该包提供了一个基础请求类?BaseRequest,该类需将?R?写成实际请求类,这样才能获取对应请求类的对象来进行相关的请求信息配置,如果请求配置与全局配置冲突,那么优先请求配置,意思就是局部请求配置会替换掉相同的全局配置。

                              strategy


                              该包提供的是缓存相关的策略,包含如下几种策略:


                              1、CacheAndRemoteStrategy:先加载缓存数据后加载网络数据;


                              2、FirstCacheStrategy:优先加载缓存数据;


                              3、FirstRemoteStrategy:优先加载网络数据;


                              4、OnlyCacheStrategy:只加载缓存数据;


                              5、OnlyRemoteStrategy:只加载网络数据。

                                subscriber


                                该包提供的是相关的订阅者,目前包含?API?请求的统一订阅者?ApiSubscriber、包含回调的订阅者?ApiCallbackSubscriber?以及包含下载回调的订阅者?DownCallbackSubscriber













                                Cache(缓存)











                                该模块提供了几种缓存方式,分别是内存缓存、磁盘缓存以及?SharedPreferences?存储。该模块主要思想是面向接口编程,提供了?ICache?接口,主要包含添加缓存、获取缓存、删除缓存、清除所有缓存以及判断是否包含该缓存这几个能力。下面将对每个缓存方式做详细的解释说明:


                                  内存缓存:内存缓存采用单例模式管理缓存对象,缓存对象为?LruCache,缓存算法采用?Lru?算法(Least Recently Used?*期最少使用算法),缓存大小为最大内存的八分之一。

                                  磁盘缓存:磁盘缓存?KEY?采用?MD5?加密,可定制缓存时长,没有定制则默认永久存储,缓存对象为?DiskLruCache,缓存算法也是?Lru?算法,缓存位置和缓存大小都可以定制,如果没有定制就会使用默认值,默认的缓存位置为该应用缓存目录下的?disk_cache目录,优先存储到?SD?卡中,默认的缓存大小为?20M。

                                  SharedPreferences 存储:SharedPreferences?存储对缓存对象进行?Base64?加密存储,可定制缓存文件名,如果没有定制则使用默认文件名?sp_cache。













                                  Event(事件总线)











                                  该模块使用?Rx?思想实现了?RxBus?功能,其?Bus?的设计思想与?EventBus?类似。其主要由以下几个核心类组成:


                                    EventBase :事件处理基类,包含粘性事件?Map?以及普通事件?Subject,也定义了获取?Flowable?以及删除粘性事件和删除粘性事件?Map?的方法。

                                    EventComposite :事件复合类,就是将需要接收事件的类中所有事件组合到一起进行处理,并提供了一个发送粘性事件的方法。

                                    EventSubscriber :事件订阅者,提供了订阅事件和分发事件的方法。

                                    EventFind :根据注解查找事件接收方法,由此得到?EventSubscriber,最后组合到一起得到?EventComposite。

                                    ThreadMode :线程模型,包含如主线程、IO线程等,通过?getScheduler(ThreadMode thread)?来获取线程调度者。


                                    事件接收采用注解方式类进行管理,事件订阅后依据注解来查找对应的事件接收地。


                                    该模块为了能将事件总线统一,定义了?IBus?接口,提供了如下四个方法:


                                    void register(Object object);

                                    也提供了?IEvent?接口,所有事件都实现该接口,这样就可以将具体的事件实现类抽离,其实也是面向接口编程。


                                    该模块也提供了插件化思想,上层可以将如?EventBus?的实现类注入该模块,那么事件的处理就会采用?EventBus?实现的策略,但这里有一个问题,由于事件接收采用的是注解方式,而?EventBus?中的注解是不同的,所以还是需要把注解事件进行统一替换,耦合性太高,目前没有发现更好的方式,如果哪位朋友有好的去耦合方式,欢迎留言交流!












                                    Loader(图片加载)











                                    该模块针对图片加载做了二次封装,面向接口编程,每个实现就是一种图片加载策略,默认采用?Glide?图片加载框架,上层也可以依需自定义实现接口?ILoader,比如?Demo?中提供的?Fresco?图片框架的实现类?FrescoLoader,其主要思想就是插件化,外部可注入任何加载策略,这样可达到高内聚低耦合。


                                    接口中提供了如下四种加载图片的方式:



                                    默认的?Glide?框架采用?provided?方式依赖,这样就只是编译时依赖,运行时不依赖,上层如果确定使用?GlideLoader 加载策略,那么还需要自己使用?compile?进行依赖,这样运行时才不会报错,GlideLoader?在初始化时也增加了如下验证机制:



                                    如果没有依赖?Glide?库则会抛出异常。












                                    Database(数据库)











                                    该模块将?GreenDao?作为底层数据库,定义了数据库的操作接口?IDatabase,统一由?DBManager?抽象类管理,由于每个实体类对应的?Dao?不一样,所以定义了抽象方法?getAbstractDao()。由于?GreenDao?的特殊性,该方法的实现类不能在框架中搭建,所有数据库操作都可以参考?Demo?中?DbHeDlper?类实现自己的数据库操作管理类,不同的?Dao?实现对应的?getAbstractDao()?方法就行。












                                    Permission(权限管理)











                                    该模块利用?Rx?思想统一管理权限的申请,一行代码搞定权限的申请问题。


                                    PermissionManager.instance().with(this).request(onPermissionCallback, Manifest.permission.CALL_PHONE);

                                    该模块很简洁,就几个类,下面分别对它们进行介绍:


                                      OnPermissionCallback:权限申请回调接口,在接口实现类中调用具体的业务逻辑。

                                      Permission:权限实体类,包含权限名称、是否授予权限以及是否显示权限申请理由变量。

                                      PermissionManager:权限管理类,也是权限申请的唯一入口,采用单例模式,需要通过?with?将当前的?Activity?对象传进去,调用?request?方法就可以进行权限申请,需要传入回调和权限列表,权限列表采用可变数组方式传入,使用示例如下:



                                        RxPermissions:权限管理核心类,该类通过传入?Activity?获取一个?Fragment?来进行权限申请回调处理,提供了一系列权限申请的方法,有多个权限单独处理回调和统一处理回调的方式,分别是?requestEach?和?request?方式。

                                        RxPermissionsFragment:权限申请回调处理?Fragment。













                                        UI











                                        UI模块,包含万能适配器、视图切换。该模块包含万能适配器和试图切换功能。适配器部分采用?ViewHolder?来管理数据的装载和展示,将数据与展示分离,提供了?DataHelper?接口来装载数据,ViewHelper?接口来处理?UI的展示。其中的?HelperAdapter?提供了适配器的常用方法,基本能满足适配器的常用需求。

                                        视图切换部分由?StatusLayoutManager?统一管理,通过传入相关配置进行视图展示处理。内部提供了?OnRetryListener?重试监听和?OnStatusViewListener?试图切换监听,并定义了一个自定义视图?StatusLayout?用来展示以下五种视图:


                                          CONTENT:内容视图;

                                          LOADING:加载视图;

                                          EMPTY:空视图;

                                          NETWORK_ERROR:网络错误视图;

                                          OTHER_ERROR:其他错误视图。













                                          最后











                                          到此,XSnow?框架的所有模块就介绍完毕了,不知各位朋友是否对该框架有了更深入的了解。


                                          以上描述有些部分可能讲解比较简单,这是因为有些模块本身不是很复杂,所以就没有做过多的讲解,如果想更清晰的了解该框架,最好的办法是直接?down?下源码观察,如果在看源码过程中有哪里不理解或觉得实现有问题而你有更好的方案都可以留言交流!


                                          源码地址:



                                          https://github.com/xiaoyaoyou1212/XSnow













                                          更多











                                          每天学*累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。


                                          如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

                                          欢迎长按下图?->?识别图中二维码或者扫一扫关注我的公众号:




友情链接: