51

Android模块化框架介绍

 5 years ago
source link: http://tinycoder.cc/2018/09/03/Android模块化框架介绍/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

模块化是一种成熟的业务解耦思想,目前已广泛应用在APP的开发中。之前写过一篇文章—— Android模块化实践 对APP模块化的过程及遇到的问题进行了介绍。具体的实例代码最近也完善的差不多了,所以写篇文章介绍一下这个项目—— SimpleProject , 一个以分层思想+模块化开发的通用框架,将会被长期维护。

项目结构

本项目是按照 Android模块化实践 中介绍的结构来开展的,所以可先看下这篇文章了解一下基本结构。项目结构如下所示:

Nf6Zjyr.png!web

其中,MainModule, BaseComponentDemo, BaseLibraryDemo和CommonBusinessDemo都是业务层模块,他们的关系如图所示:

VrUjqqN.png!web

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) {
        /**
         * 点击推送通知时的回调
         */
    }
});

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK