模块化是一种成熟的业务解耦思想,目前已广泛应用在APP的开发中。之前写过一篇文章——Android模块化实践对APP模块化的过程及遇到的问题进行了介绍。具体的实例代码最近也完善的差不多了,所以写篇文章介绍一下这个项目——SimpleProject, 一个以分层思想+模块化开发的通用框架,将会被长期维护。
项目结构
本项目是按照Android模块化实践中介绍的结构来开展的,所以可先看下这篇文章了解一下基本结构。项目结构如下所示:
其中,MainModule, BaseComponentDemo, BaseLibraryDemo和CommonBusinessDemo都是业务层模块,他们的关系如图所示:
MainModule是整个APP的主模块,用来实现APP中主页和路由跳转相关的逻辑,同时也作为Application与其他模块关联的枢纽。
BaseComponentDemo, BaseLibraryDemo和CommonBusinessDemo是子业务模块,都依赖于library目录中的三个公共模块。这三个模块一方面是用来展示业务模块化实现过程,另一方面也是library中三个模块的示例代码。所以这三个模块中没有什么核心的代码,下面主要介绍一下library中的三个模块。
建议
默认情况下,创建的Module都是在Project目录下,但是当模块比较的多的时候,定位代码时还是比较繁琐的,所以推荐将底层的Module放在创建的library目录中,然后在setting.gradle中对Module的路径进行配置:
project(':baselibrary').projectDir = new File('library/baselibrary')
project(':basecomponent').projectDir = new File('library/basecomponent')
project(':commonbusiness').projectDir = new File('library/commonbusiness')
复制代码
有时候也会引入一些第三方的Module, 此时也可将其放在library目录中,或者创建其他的目录用来存放第三方的Module,然后在setting.gradle中进行配置。这样Project目录下只有业务层的Module,项目结构看起来会清晰很多。
baselibrary
baselibrary是Common组件层的实现,包括各种常用的工具类,通用的UI库,数据源的封装(包括网络,文件,数据库)。
工具类
commonutils中包含了丰富的工具类,具体介绍如下:
AppUtil: App相关的一些操作,如版本号,进程号,是否已安装,是否正在运行,是否运行在前台等;
BitmapUtil: Bitmap相关的一些操作,如缩放,与Drawable之间的转换等;
CollectionUtil: 与集合/数组相关的操作;
ConvertUtil: 基本类型与String之间的转换操作;
DateTimeUtil: 时间格式化相关的操作;
DeviceUtil: 设备相关的操作,如获取系统的各种参数;
EncryptUtil: 加密操作,如MD5, 隐藏手机号,邮箱等操作;
FileUtil: 与文件相关的操作;
InputMethodUtil: 与键盘相关的操作,如打开/隐藏键盘,键盘弹出时调整EditText位置等;
LaunchUtil: 跳转到其他APP的操作,如打开电话,短信等;
LogUtil: 日志工具类;
NetworkUtil: 与网络相关的工具类,如获取网络参数,获取联网状态等;
PermissionUtil: 权限验证类;
RomUtil: 判断手机ROM的类型;
ScrollStateUtil: 判断可滑动View是否到达顶部或底部;
SpannableStringUtil: 富文本工具类;
ToastUtil: Toast工具类
VerificationUtil: 验证工具类,如手机号,邮箱,身份证,是否为中文等;
ViewBgUtil: 动态设置View背景的工具类;
ShadowDrawable: 被View设置阴影的工具类;
复制代码
数据源
Android中常用的数据源也就四个:SharePreference,文件,数据库和网络。
SharePreference
SharePreference是Android提供的一种以key-value结构用来存储少量数据的方式,本质上也是文件的存储方式,但是直接使用时比较繁琐,为了简化调用过程,项目中提供了它的封装版——PreferencesManager,支持同步和异步两种方式。
文件
文件方式就是简单的文件读写,这里的文件缓存使用了ACache。
数据库
与文件一样,数据库也算是Android中的低频数据源,直接使用GreenDAO即可。
网络
网络是Android开发中主要的数据源,会被大量使用,所以需要进行简单的封装,从而简化网络请求的过程。网络框架使用了Retrofit。 http目录中是整个网络框架的封装,其中提供了公共参数,缓存,Cookie,认证四种拦截器。同时提供了Gson数据转换的兼容类,避免异常数据转换时因类型不匹配而导致的闪退。
网络请求示例代码:
HttpManager.getInstance().executeRequest(apiService.getUserInfo(), new ResponseProcessor.RequestListener<UserInfoBean>() {
@Override
public void onSuccess(UserInfoBean response) {
// 请求成功
}
@Override
public void onFailure(int code, String msg) {
// 请求失败
}
});
复制代码
通用UI
通用UI是一些自定义View,放在这个位置的自定义View需要有高度的可定制性和与业务无关的特征。
CircleProgressBar: 圆形进度条;
LevelView: 类似Uber的等级选择器;
RefreshLayout: 下拉刷新、上拉加载组件;
ResilienceListView: 下拉可回弹的ListView;
ShapeImageView: 可定义形状的ImageView;
TabLayout: 类似微信底部的Tab组件;
复制代码
basecomponent
basecomponent是基础业务层的实现,用于统一APP的代码结构和UI风格。主要包括Activity&Fragment,Dialog的封装。
Activity & Fragment
Activity&Fragment作为Android中承载View的组件,它们的风格基本决定了APP的整体风格。其实就目前主流的设计,Activity/Fragment的UI也就几种状态:
- 页面加载时是否有加载圈;
- 页面是否有NavigationBar;
总的来说也就这4种情况的组合。针对这4种情况提供了以下封装类:
- BaesActivity 不需要网络请求的Activity;
- BaesProgressActivity 需要网络请求的Activity(页面默认显示加载圈);
- BaseFragment 不需要网络请求的Fragment;
- BaseProgressFragment 需要网络请求的Fragment(页面默认显示加载圈);
而对于NavigationBar也提供了三种样式: 白底,透明,半透明,根据需要进行设置即可。
Dialog
Dialog也是Android开发中常用的UI组件,这里提供了普通对话框,单选对话框,多选对话框,底部对话框四种方式,同时对每一种提供了自定义样式和Material样式两种风格,具体可参考Android通用UI组件之Dialog
commonbusiness
commonbusiness是公共组件层的实现。其中包括APP中一些通用的功能,如登录验证,权限验证,第三方登录,分享,支付,推送等功能。
登录验证
在Android开发中,有一些页面是需要登录才能查看的,如果直接使用判断登录状态的方式,就是显得很繁琐。所谓为了简化这种验证过程,项目中提供了基于AOP的方式,开发者中需要验证登录状态的方法上面使用@CheckLogin注解即可。具体代码参考aspect目录。
权限验证
Android6.0之后权限的获取都是通过动态获取的,但是获取的过程比较繁琐,所以为了简化权限的获取过程,这里也使用了基于AOP的权限申请。在需要申请权限时,使用@CheckPermission注解即可,代码如下所示:
@CheckPermission(permissions = {Manifest.permission.CAMERA,}, permissionDesc = "没有权限无法使用相机", settingDesc = "快去设置中开启权限")
private void setUserIcon() {
}
复制代码
当用户拒绝了权限申请后,弹出toast提示permissionDesc中的内容,当勾选了【不再询问】拒绝后,再次申请就会弹出Dialog, 提示内容为settingDesc,当然,这两个字段也是有默认值的,如果不需要详细的提示,可不用设置。
第三方登录
现在的应用除了内置的登录功能外,为了便于用户使用,通常还会提供第三方登录的功能。通常使用的第三方登录也就微信,微博,QQ三种。这里为第三方登录提供了统一的接口,需要登录时直接调用即可。
分享
目前APP的主要分享渠道是微信,微博和QQ,所以分享模块也只集成了这三种分享方式。使用时只需要在相应的开发平台上创建应用并配置参数,然后在分享模块中配置参数即可。当然,项目中也提供了一个分享页面——ShareActivity,分享时调用ShareActivity.enter(...)方法即可。
支付
项目中集成了微信支付和支付宝支付,并且为支付提供了统一了接口,使用时只需要将从后台获取的参数传入即可
支付宝支付
// requestStr是后台返回的订单相关的参数
PayManager.getInstance(PayActivity.this).payByAliPay(this, requestStr, new PayManager.AliPayListener() {
@Override
public void onSuccess() {
ToastUtil.show("支付成功");
}
@Override
public void onFailure(Exception e) {
ToastUtil.show("支付失败" + e.getMessage());
}
});
复制代码
微信支付
// 根据后台返回的微信支付的参数构造PayRequestBean对象
PayRequestBean payRequest = new PayRequestBean(...)
PayManager.getInstance(PayActivity.this).payByWeChat(payRequest, new PayManager.AliPayListener() {
@Override
public void onSuccess() {
ToastUtil.show("支付成功");
}
@Override
public void onFailure(Exception e) {
ToastUtil.show("支付失败" + e.getMessage());
}
});
复制代码
推送
目前推送的推送率基本都是通过第三方推送SDK组合的方式来保障的,项目中集成了小米,华为,极光推送三种方式,根据机型动态设置推送方式,小米手机使用小米推送,华为推送使用华为推送,其他的品牌则使用极光推送。开发时只需要在Applicataion中调用PushManager的init方法进行初始化,并且设置推送的监听即可。
PushManager.getInstance().initPush(getApplicationContext(), "小米推送的appId",
"小米推送的appKey");
PushManager.getInstance().setPushListener(new PushListener() {
@Override
public void onReceiveMessage(Context context, int pushChannel, Object object) {
/**
* 接收到自定义消息时的回调
*/
}
@Override
public void onReceiveNotification(Context context, int pushChannel, Object object) {
/**
* 接收到通知时的回调
*/
}
@Override
public void onNotificationClicked(Context context, int pushChannel, Object object) {
/**
* 点击推送通知时的回调
*/
}
});
复制代码
项目地址
总结
目前的项目已经有个大概的轮廓了,但是细节方面还有许多需要完善的,同时实例代码的展示也还不够详细,随后会进一步完善,感兴趣的小伙伴可关注一下。