因为有使用的朋友提到 XSnow
框架信息量有点大,但愿能有篇文章详细介绍框架中每一个模块的细节,因此本文会围绕该框架将每个模块的相关构思和重要技术点作一个详细的剖析,让使用该框架的朋友对 XSnow
有一个清晰的认识。html
因为 XSnow
框架是基于 RxJava2
和 Retrofit2
打造的,其中也依赖了如网络基础库 OkHttp
、图片加载库 Glide
、数据库基础库 GreenDao
,因此使用该项目的朋友须要对这几个基础框架有基本的认识,下面将对这几个框架作一个简单的说明。java
熟悉的朋友可能知道该框架是属于 ReactiveX
编程库的一员,这是一种新的编程思想,通常都把它叫作响应式编程思想,对于使用该思想的优点在这里就不赘述了,感兴趣的朋友能够看看这篇文章 ReactiveX 文档中文翻译。git
RxJava
主要的模式就是观察者模式,何为观察者模式,能够简单的理解为:两个对象观察者与被观察者,其中观察者与被观察者创建了订阅关系,若是被观察者发生了变化那么须要及时通知观察者,观察者收到通知后作出相应的处理。描述可能会有点绕,举个通俗易懂的例子吧,好比说:顾客去买蛋糕这样一个场景(把顾客和蛋糕店店员分别看作观察者与被观察者),因为蛋糕是现作须要必定时间才能完成,顾客在购买时通常会先付钱给店员拿到一个付款凭证后离开去忙其余事,这样他们就创建了购买关系(创建订阅关系),店员在作完蛋糕后(被观察者发生变化),店员就会通知顾客来拿(消息通知到观察者),顾客在收到店员通知后前来拿蛋糕(观察者收到通知后作出相应的处理)。到这里,一个完整的观察者模式场景就讲解完毕,但愿能帮助朋友们加深对观察者模式的理解。github
下面继续讲解对 RxJava
的理解,先想象一个这样的场景,有一台万能机器,它能够生产任何东西,它有一个输入端、一个输出端,中间有不少核心组件,好比说转换器、转移器等,它们对外部都是隐藏的,可是外部有一个控制终端,能够输入任何想要的规则,机器就会根据规则,将输入端的东西经过终端制定的规则输送到输出端。RxJava
就是这样一台万能机器,它拥有数据输入端、数据输出端,中间也有不少能够操控数据的规则,好比说各类操做符、线程转换,它们都有一个目的,就是如何让数据源经过必定规则进行输出。算法
以上的讲解只是为了让你对 RxJava
有一个清晰的认识,不牵扯具体的技术细节,若是想详细了解的能够去看看给初学者的 RxJava2.0 教程,这是一个系列,看完这些文章,基本就可使用 RxJava
作一些基础的功能了,这个系列是针对 RxJava2
的,若是想了解 RxJava
初版,想看看两个版本到底发生了什么改变,那么能够看看给 Android 开发者的 RxJava 详解以及 RxJava2 vs RxJava1.数据库
Retrofit
简单来讲就是一个基于 OkHttp
的 RESTful API
请求工具。RESTful
是一种架构风格,它的特色是资源、统一接口、URI
和无状态,若是想更详细的了解 RESTful
能够看看RESTful 架构风格概述。编程
Retrofit
在使用时其实就充当了一个适配器(Adapter
)的角色,主要是将一个 Java
接口翻译成一个 HTTP
请求对象,而后用 OkHttp
去发送这个请求。其中核心思想就是动态代理机制,什么是动态代理,就是当你要调用某个 Class
的方法前或后,插入你想要执行的代码。通俗来说,就是你要执行某个操做的先后须要增长一些操做,好比查看用户我的信息前须要判断用户是否登陆,用户访问数据库后想清除用户的访问记录等操做。api
Retrofit
的设计很是插件化且轻量级,高内聚且低耦合。Retrofit
主要定义了 4 个接口:数组
Callback<T>
:请求数据的返回;Converter<F, T>
:对返回数据进行解析,通常用 GSON
;Call<T>
:发送请求,Retrofit
默认的实现是 OkHttpCall<T>
,也能够依需自定义 Call<T>
;CallAdapter<T>
:将 Call
对象转换成其余对象,如转换成支持 RxJava
的 Observable
对象。Retrofit
进行网络请求的过程:缓存
Retrofit
对象和 Method
对象获取 callAdapter
、responseType
以及 responseConverter
三个对象;Method
中的注解以及进行一系列的检查获得中心管理对象 ServiceMethod
;ServiceMethod
对象获取实际执行的 Call
对象执行 Http
请求。以上讲解只是对 Retrofit
的核心功能作了相关的解释,若是想更详细的了解 Retrofit
能够看看拆轮子系列:拆 Retrofit
OkHttp
是一个高效的 HTTP
库,它的整体设计图以下(图片来源:泡在网上的日子):
OkHttp
的请求由 OkHttpClient
统一管理,采用的是门面模式,OkHttpClient
拥有子模块的全部配置和参数,并将请求分发到相应的子系统。它由如下几个核心子系统组成:路由、链接协议、拦截器、代理、安全性认证、链接池以及网络适配。主要是经过 Dispatcher
不断从 RequestQueue
中取出请求(Call
),根据是否已缓存调用 Cache
或 Network
这两类数据来获取某个接口,再从内存缓存或是服务器取得请求的数据。该引擎有同步和异步请求,同步请求经过Call.execute()
直接返回当前的 Response
,而异步请求会把当前的请求(AsyncCall
)Call.enqueue
添加到请求队列中,并经过回调(Callback
)的方式来获取最后结果。
OkHttp
中的 Interceptor
(拦截器)方式对于总体的设计提供了很大的帮助,它采用的是责任链模式,它不仅是负责拦截请求进行一些额外的处理(例如增长请求头),实际上它把实际的网络请求、缓存、透明压缩等功能都统一了起来,每个功能都只是一个 Interceptor
,它们再链接成一个 Interceptor.Chain
,环环相扣,最终圆满完成一次网络请求。
以上讲解只是对 OkHttp
的流程作了相关的解释,若是想更详细的了解 OkHttp
能够看看拆轮子系列:拆 OkHttp。
Glide
是为图片加载而生,一行代码Glide.with(this).load(url).into(imageView);
就搞定图片的加载。使用很是简单,若是想详细了解的,这里推荐郭霖的 Glide 源码解析,Android 图片加载框架最全解析,这是一个系列,看完后对于 Glide 基本就能知道怎么用和为啥要这样用了。
GreenDao
是一个将对象映射到 SQLite
数据库中的轻量且快速的 ORM
解决方案。若是想更详细的了解 GreenDao
能够看看Android 数据存储之 GreenDao 3.0 详解。
XSnow
框架利用的相关技术有个直观的感觉,若是想详细了解的,上面在每一个基础库后面都备注了我的认为比较好的文章,能够当作学习该框架的参考。该模块是 XSnow
框架的核心功能,其核心思想就是将请求分离和基于动态配置,采用门面模式,上层不用关系具体实现细节,只须要简单配置相关的请求信息就能够达到完整的网络请求功能。该模块相对于其余模块代码量比较大,下面将会对该模块下的每个包进行详细拆分讲解,如今咱们首先来看看 ViseHttp
类,该类至关于该模块的门面类,也是网络请求的惟一入口类,全部的请求都是由该类构建,如:
GET
方式请求对象;POST
方式请求对象;HEAD
方式请求对象;PUT
方式请求对象;PATCH
方式请求对象;OPTIONS
方式请求对象;DELETE
方式请求对象;该类还提供了根据 tag
中断单个网络请求以及中断全部网络请求功能,也提供了根据 key
删除缓存和清除全部网络缓存功能。必须注意的是,在应用初始化时必须调用该类的初始化方法
ViseHttp.init(this);复制代码
以及相关的网络配置
ViseHttp.CONFIG()
//配置请求主机地址
.baseUrl("http://10.8.4.39/")
//配置全局请求头
.globalHeaders(new HashMap<String, String>())
//配置全局请求参数
.globalParams(new HashMap<String, String>())
//配置读取超时时间,单位秒
.readTimeout(30)
//配置写入超时时间,单位秒
.writeTimeout(30)
//配置链接超时时间,单位秒
.connectTimeout(30)
//配置请求失败重试次数
.retryCount(3)
//配置请求失败重试间隔时间,单位毫秒
.retryDelayMillis(1000)
......;复制代码
这样才能在应用中调用相关的网络请求功能。若是没有初始化,在调用网络请求时该模块会抛出以下异常信息:
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
存储,存储对象以十六进制进行保存。
exception
该包提供网络请求相关异常类,目前提供了请求异常统一处理类 ApiException
,可用来断定请求失败的缘由。
func
该包提供一些数据转换类,目前提供了由 ResponseBody
对象转 T
的 ApiFunc<T>
类以及由 Observable<? extends Throwable>
转 Observable<?>
的 ApiRetryFunc
类。ApiRetryFunc
类主要用来处理网络超时重试机制,可传入重试次数和重试间隔时间,这些均可以在配置类中进行配置。
interceptor
该包提供的是一系列的拦截器类,这个包也算是该模块的核心包,基本大部分功能均可以采用拦截器的方式来提供,目前该包下面包含以下拦截器:
一、GzipRequestInterceptor
:包含Gzip压缩的请求拦截;
二、HeadersInterceptor
:请求头拦截;
三、HttpLogInterceptor
:Http日志打印拦截;
四、NoCacheInterceptor
:无缓存拦截;
五、OfflineCacheInterceptor
:离线缓存拦截;
六、OnlineCacheInterceptor
:在线缓存拦截;
七、UploadProgressInterceptor
:上传文件进度展现拦截。
mode
该包提供的是相关的实体类。
request
该包提供的是全部请求相关的类,全部的网络请求都须要建立一个请求对象,该包提供了一个基础请求类 BaseRequest<R extends BaseRequest>
,该类需将 R
写成实际请求类,这样才能获取对应请求类的对象来进行相关的请求信息配置,若是请求配置与全局配置冲突,那么优先请求配置,意思就是局部请求配置会替换掉相同的全局配置。
请求类中提供了一系列请求头配置、请求参数配置等信息,若是是 POST
请求还提供了上传 JSON
字符串、上传表单等方式,而若是是上传文件则提供了添加文件、添加字节数组和添加流的方式。
因为带缓存请求和不带缓存请求返回的结果不同,因此须要分开处理,故有 cacheExecute
和 execute
的区分。
strategy
该包提供的是缓存相关的策略,包含以下几种策略:
一、CacheAndRemoteStrategy
:先加载缓存数据后加载网络数据;
二、FirstCacheStrategy
:优先加载缓存数据;
三、FirstRemoteStrategy
:优先加载网络数据;
四、OnlyCacheStrategy
:只加载缓存数据;
五、OnlyRemoteStrategy
:只加载网络数据。
缓存策略采用面向接口编程原则,定义了一个缓存策略接口 ICacheStrategy<T>
,并将具体的策略实现交由各个子类。
subscriber
该包提供的是相关的订阅者,目前包含 API
请求的统一订阅者 ApiSubscriber<T>
、包含回调的订阅者 ApiCallbackSubscriber<T>
以及包含下载回调的订阅者 DownCallbackSubscriber<T>
。
该模块提供了几种缓存方式,分别是内存缓存、磁盘缓存以及 SharedPreferences
存储。该模块主要思想是面向接口编程,提供了 ICache
接口,主要包含添加缓存、获取缓存、删除缓存、清除全部缓存以及判断是否包含该缓存这几个能力。下面将对每一个缓存方式作详细的解释说明:
LruCache
,缓存算法采用 Lru
算法(Least Recently Used
近期最少使用算法),缓存大小为最大内存的八分之一。KEY
采用 MD5
加密,可定制缓存时长,没有定制则默认永久存储,缓存对象为 DiskLruCache
,缓存算法也是 Lru
算法,缓存位置和缓存大小均可以定制,若是没有定制就会使用默认值,默认的缓存位置为该应用缓存目录下的 disk_cache
目录,优先存储到 SD
卡中,默认的缓存大小为 20M
。SharedPreferences
存储对缓存对象进行 Base64
加密存储,可定制缓存文件名,若是没有定制则使用默认文件名 sp_cache
。该模块使用 Rx
思想实现了 RxBus
功能,其 Bus
的设计思想与 EventBus
相似。其主要由如下几个核心类组成:
Map
以及普通事件 Subject
,也定义了获取 Flowable
以及删除粘性事件和删除粘性事件 Map
的方法。EventSubscriber
,最后组合到一块儿获得 EventComposite
。getScheduler(ThreadMode thread)
来获取线程调度者。事件接收采用注解方式类进行管理,事件订阅后依据注解来查找对应的事件接收地。
该模块为了能将事件总线统一,定义了 IBus
接口,提供了以下四个方法:
void register(Object object);
void unregister(Object object);
void post(IEvent event);
void postSticky(IEvent event);复制代码
也提供了 IEvent
接口,全部事件都实现该接口,这样就能够将具体的事件实现类抽离,其实也是面向接口编程。
该模块也提供了插件化思想,上层能够将如 EventBus
的实现类注入该模块,那么事件的处理就会采用 EventBus
实现的策略,但这里有一个问题,因为事件接收采用的是注解方式,而 EventBus
中的注解是不一样的,因此仍是须要把注解事件进行统一替换,耦合性过高,目前没有发现更好的方式,若是哪位朋友有好的去耦合方式,欢迎留言交流!
该模块针对图片加载作了二次封装,面向接口编程,每一个实现就是一种图片加载策略,默认采用 Glide
图片加载框架,上层也能够依需自定义实现接口 ILoader
,好比 Demo
中提供的 Fresco
图片框架的实现类 FrescoLoader
,其主要思想就是插件化,外部可注入任何加载策略,这样可达到高内聚低耦合。
接口中提供了以下四种加载图片的方式:
void loadNet(ImageView target, String url, Options options);复制代码
void loadResource(ImageView target, int resId, Options options);复制代码
void loadAssets(ImageView target, String assetName, Options options);复制代码
void loadFile(ImageView target, File file, Options options);复制代码
默认的 Glide
框架采用 provided
方式依赖,这样就只是编译时依赖,运行时不依赖,上层若是肯定使用 GlideLoader
加载策略,那么还须要本身使用 compile
进行依赖,这样运行时才不会报错,GlideLoader
在初始化时也增长了以下验证机制
try {
Class.forName("com.bumptech.glide.Glide");
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Must be dependencies Glide!");
}复制代码
若是没有依赖 Glide
库则会抛出异常。
该模块将 GreenDao
做为底层数据库,定义了数据库的操做接口 IDatabase<M, K>
,统一由 DBManager<M, K>
抽象类管理,因为每一个实体类对应的 Dao
不同,因此定义了抽象方法 getAbstractDao()
。因为 GreenDao
的特殊性,该方法的实现类不能在框架中搭建,全部数据库操做均可以参考 Demo
中 DbHeDlper
类实现本身的数据库操做管理类,不一样的 Dao
实现对应的 getAbstractDao()
方法就行。
该模块利用 Rx
思想统一管理权限的申请,一行代码搞定权限的申请问题。
PermissionManager.instance().with(this).request(onPermissionCallback, Manifest.permission.CALL_PHONE);复制代码
该模块很简洁,就几个类,下面分别对它们进行介绍:
PermissionManager:权限管理类,也是权限申请的惟一入口,采用单例模式,须要经过 with
将当前的 Activity
对象传进去,调用 request
方法就能够进行权限申请,须要传入回调和权限列表,权限列表采用可变数组方式传入,使用示例以下:
PermissionManager.instance().with(this).request(new OnPermissionCallback() {
@Override
public void onRequestAllow(String permissionName) {
DialogUtil.showTips(mContext, getString(R.string.permission_control),
getString(R.string.permission_allow) + "\n" + permissionName);
}
@Override
public void onRequestRefuse(String permissionName) {
DialogUtil.showTips(mContext, getString(R.string.permission_control),
getString(R.string.permission_refuse) + "\n" + permissionName);
}
@Override
public void onRequestNoAsk(String permissionName) {
DialogUtil.showTips(mContext, getString(R.string.permission_control),
getString(R.string.permission_noAsk) + "\n" + permissionName);
}
}, Manifest.permission.CALL_PHONE);复制代码
Activity
获取一个 Fragment
来进行权限申请回调处理,提供了一系列权限申请的方法,有多个权限单独处理回调和统一处理回调的方式,分别是 requestEach
和 request
方式。Fragment
。该模块包含万能适配器和试图切换功能。适配器部分采用 ViewHolder
来管理数据的装载和展现,将数据与展现分离,提供了 DataHelper
接口来装载数据,ViewHelper
接口来处理 UI
的展现。其中的 HelperAdapter
提供了适配器的经常使用方法,基本能知足适配器的经常使用需求。
视图切换部分由 StatusLayoutManager
统一管理,经过传入相关配置进行视图展现处理。内部提供了 OnRetryListener
重试监听和 OnStatusViewListener
试图切换监听,并定义了一个自定义视图 StatusLayout
用来展现如下五种视图:
到此,XSnow
框架的全部模块就介绍完毕了,不知各位朋友是否对该框架有了更深刻的了解。
以上描述有些部分可能讲解比较简单,这是由于有些模块自己不是很复杂,因此就没有作过多的讲解,若是想更清晰的了解该框架,最好的办法是直接 down
下源码观察,若是在看源码过程当中有哪里不理解或以为实现有问题而你有更好的方案均可以留言交流!
源码地址:github.com/xiaoyaoyou1…,源码地址中提供了详细的使用文档,里面有版本介绍以及QQ群等信息,若是喜欢该框架不妨点点 star
并分享给身边的朋友,让更多的朋友参与进来,谢谢你们!