美文网首页优秀案例
〔两行哥〕快速搭建AndroidApp的统一UI框架

〔两行哥〕快速搭建AndroidApp的统一UI框架

作者: 两行哥 | 来源:发表于2017-05-23 00:35 被阅读176次

本项目已经上传至码云,有兴趣的同志可以参考。

码云:https://git.oschina.net/xuzhaoyu/demo.git

当产品原型评审后,产品经理就会拿着一份产品原型规范,我们程序猿们需要做的就是在完成一半的界面上开始缝缝补补的工作,这种苦逼的工作经历想必大家都经历过。为了减轻产品原型变更带来的代码重构痛苦,大家都会将自己App的某些逻辑封装,便于统一修改。今天两行哥和大家分享上一个项目中封装的统一UI管理框架。

一、基本概述

统一UI管理,即在用户交互中,根据交互结果(网络请求返回数据),自动切换界面(弹出提示框),以两行哥上个项目的全局说明为例:

1.全局交互(如全页面请求网络、全页面数据库查询等耗时操作)

图1 全局交互

2.局部交互(如用户点击页面上的收藏按钮等耗时操作)

图2 局部交互

3.框架设计原则

对于一个项目的全局框架而言,应当具备以下特性:

a.公用性。仅封装涵盖大部分页面的公用逻辑,非公用逻辑应当在其子类或使用额外的接口进行封装,不应当在项目全局框架中封装。

b.独立性。框架应当独立于具体逻辑,即应当与具体逻辑无关,比如依赖于某个存储于SP中的数据,这是不正确的。框架的独立性保证了框架的可移植性,未来的项目可以直接嵌套使用。

本框架设计遵循上述两个原则,仅封装基本逻辑,且不依赖任何细节逻辑,具备可移植性。

4.其他说明

本框架设计中使用了RxJava的基础逻辑,关于RxJava的使用本文不做说明。

二、设计逻辑

1.关于全局网络请求的次数

全局网络请求是全局交互中的一种。通常情况下我们一个页面只有一个网络请求,但是在某些情况下,某些页面需要多次请求数据。为了保证客户端网络访问的稳定性及避免NPE,不推荐进行并发网络请求,通常在第一次网络请求成功的回调中进行第二次网络请求,以此类推。

以下图为例,此页面共有3次网络请求。请求”期权课“的课程封面、标题、价格——请求课程简介——请求是否已经购买。

那么当刚进入该页面时应该向用户展示“载入中”界面,当且仅当3个网络请求都成功,才会展示网络访问成功的界面(即图3的界面),否则应当展示网络连接失败的界面(图1的第二个界面)。

全局数据库操作等其他耗时操作,同上逻辑进行处理。

图3 网络请求说明

2.全局网络请求的页面层叠

本统一UI管理框架基本思想为:将图1的三个状态界面(加载中、网络连接失败、无数据)以及加载成功的界面(如图3的界面)封装到同一个ViewGroup中,覆盖层叠,考虑性能优化,推荐使用FrameLayout。

根据网络请求的结果(网络框架请求的回调方法),显示一个界面,隐藏其他3个界面。

例如,网络访问成功,显示加载成功界面,将加载中、网络连接失败、无数据三个状态界面隐藏。

3.局部网络请求

局部网络请求是局部交互的一种。局部网络请求中,根据服务器返回的result,会有三种状态:成功、失败、加载中(操作中),前两者在显示几秒后消失,最后一个不会自动消失,只有在网络请求成功后才消失。其中成功与失败的提示使用自定义Toast实现,加载中的提示使用自定义Dialog实现。原因如下:

a.在成功或失败操作后,有时候会有关闭当前页面或进入另外一个页面的需求。Dialog的存活依赖于前台Acitivity(栈顶的Activity)。假设提示的时间为1s(通过Timer等设置Dialog消失的时间为1000毫秒),一旦我们finish()当前Activity或者startActivity()另外启动Activity,而1s的时间未到,那么此Dialog必定会leak,导致闪退或内存泄露。假设产品逻辑为登陆界面(LoginActivity)点击”立即注册“,跳转到注册界面(RegisterActivity)点击”完成注册并登陆“,弹出提示框”注册成功“,1秒钟后消失,同时销毁后台的LoginActivity和RegisterActivity,并进入主界面(MainActivity)。此时使用Dialog的逻辑将会变得复杂,拓展性不强。因此使用自定义Toast实现,则避免了此类问题。

b.由于加载中提示框消失的时间不确定(由服务器返回数据时间决定),因此需要自定义toast的置于顶层并永不消失,并在网络请求成功后调用toast消失的方法,此时自定义toast本质是悬浮窗(类似360悬浮球)。这在安卓7.0中需要动态申请额外的权限,降低了用户体验,同时这种也不是Google提倡的方法。因此使用自定义Dialog实现,还可以setCancelable(false)来拦截用户对下层页面的操作,避免用户在一个网络请求过程中(加载中)进行其他交互或发起其他网络请求。

三、代码实现

1.框架结构

图4 框架结构

BaseActivity:封装局部交互的提示框(3种),继承于AppCompatActivity,可根据项目需要封装与全局交互无关(全局网络请求无关)的其他逻辑;

BaseFragment:同BaseActivity,继承于Fragment;

BaseNetActivity:封装全局交互(全局网络请求)的状态界面,继承于BaseActivity,可根据项目需要封装全局交互相关的其他逻辑;

BaseNetFragment:同BaseNetActivity,继承于BaseFragment;

BaseNetPage:封装全局交互(全局网络请求)的状态界面的ViewGroup,本文中继承于FrameLayout;

LoagingDialog、TipToast:封装局部交互(加载中、操作成功、操作失败)的提示框;

INetAccess:定义全局交互流程方法的接口;

NetPageState:定义全局交互类型的枚举类(加载中、加载成功、加载失败、空数据);

TipType:定义局部交互类型的枚举类,同NetPageState。

2.关键代码

a.BaseNetPage

分别创建SuccessView、LoadingView、ErrorView、EmptyView对应全局交互的4种状态页面,并添加到BaseNetPage中。onReloadClick(v)为抽象方法,用于暴露网络加载失败后“重新连接”按钮的点击事件。createSuccessView()同样为抽象方法,由于每个页面加载成功后各不相同,所以通过抽象方法暴露并由Activity或Fragment各自传入,即“谁用谁传”。

图5 initView()方法 图6 暴露抽象方法

showPage()方法主要依托RxJava异步框架。getEmitter(e)为抽象方法,用于暴露ObservableEmitter对象。mStates为一个记录多次网络请求结果的集合,如3次请求,{成功,成功,失败},则会显示错误界面,如2次请求,{成功,成功},则会显示加载成功后的界面。changePageState()用于改变界面的显示。

图7 RxJava异步框架

成员变量mCurrentState初始化值为LOADING,即刚进行网络请求或其他耗时操作时,应当显示加载中的界面。checkNetData(obj)为检查网络数据返回bean的方法。

图8 检查数据的逻辑

changePageState()的逻辑为将4个界面全部隐藏,然后根据mCurrentState自动切换页面。

图9 改变页面的显示

b.BaseNetActivity

在BaseNetActivity中定义成员变量mNetPage(BaseNetPage)并初始化。在getEmitter()方法中,将emitter记录为成员变量。

图10 初始化BaseNetPage

用构建者模式定义onNetNext()、setNetComplete()、setNetError()方法,用于执行下一次网络请求、网络请求完成、网络请求失败。

图11 定义多次网络请求的标记方法

c.MainActivity

网络请求的伪代码。UI框架会根据传入的bean自动切换界面。在最后一次网络请求后需要调用setNetComplete()方法标记网络请求已经完成。

图12 网络请求伪代码

碍于篇幅,本文关键代码仅阐述关键逻辑。BaseNetFragment逻辑与BaseNetActivity大致相同。局部交互提示框逻辑较为简单,本文不再阐述。

本项目已经上传至码云及百度网盘,有兴趣的同志可以参考。

码云:https://git.oschina.net/xuzhaoyu/demo.git

相关文章

网友评论

    本文标题:〔两行哥〕快速搭建AndroidApp的统一UI框架

    本文链接:https://www.haomeiwen.com/subject/xfphxxtx.html