在常规的业务开发中,我们往往是先构建界面元素,然后在Activity中赋能界面元素相关业务能力,譬如下图所示的编辑采购订单场景:
- 【有形】我们往往是要构建整体的界面,这个界面往往由一些组合式控件或者布局的集合构成;
- 【有神】原始的控件是不具备业务能力的,我们往往会在Activity中通过给控件setClicklistener等方式,使得界面元素具备一定的业务能力。譬如:
- 点击“供应商组合控件”,会跳转到供应商选择界面
- 选择供应商后,“供应商组合控件”会进行界面上的刷新
- 同时,也要存储新选择的供应商,用于“最终提交数据”的构建
- 【血肉】作为编辑界面,我们往往会有一个“初始数据”,进入界面后要将“初始数据”中的各个成员属性,赋值到界面元素上
- 界面字符串。 成员属性往往是另一个Class的一个对象实例,譬如供应商(包含id、名称、分组等),这样的成员对象体现在界面上基本都是一个字符串,这就是界面字符串
- 成员实例对象。 界面字符串对应的真实数据,一方面用于“最终提交数据”的构建,一方面在进行界面业务操作(譬如跳转)时,往往需要传递到选择界面作为默认选择数据
- 【凝练】最终,在经过一系列的输入、选择等业务操作后,要通过界面元素最终收集到一个“最终提交数据”
由此可以看到,我们将大量的业务代码充斥在Activity中,而且仅实现了界面控件级别的复用,业务级别的代码基本都是各种复制,由此也催生出一种想法:
我们能不能做到业务控件级别的复用?
这就是本篇《业务套件》的由来,我们期望可以达成:
- 赋能基础的界面控件以业务能力
- 可以内置业务动作
- 可以在业务动作响应后,自动更新界面字符串
- 可以在更新界面元素后,将新的“成员实例对象”存储起来,用于“最终提交数据”的构建
- 可以通过构建界面控件列表,来构建出整体的界面(类似于List的使用,但是data内置view构建能力)
- 可以将“初始数据”的成员属性自动映射到对应界面控件的界面字符串上
- 可以从界面控件上收集数据,自动映射到“最终提交数据”的成员属性上
时序图
为了方便理解,我们在最开始先针对上述提及的4个核心过程,分别提供
界面构造过程
控件构造过程如下图
查看原图
动作响应过程
vo到界面过程
界面到view过程
一、UiViewPool 业务控件的视图控件池
其核心承载功能就是,根据 业务控件类型,生成其真实的视图控件
public interface UiViewPool {
/**
* 根据 业务控件类型, 返回对应的 真实视图控件
* @param uiType 业务控件类型 {@link com.sangfor.pocket.uin.newway.UiItemTypes.ViewType}
* @param parant 当前控件将被加入的父布局
* @return 真实的视图控件
*/
View getView(int uiType, ViewGroup parant);
}
1.1 业务控件UiType和视图控件ViewType的区别与转换
- 视图控件
- 对应 UiItemTypes.ViewType
- 一种真实的视图控件样式,譬如TextView、LinearLayout、TextImageNormalForm等
- 业务控件
- 对应 UiItemTypes.UiType
- 一种 业务控件样式,是针对ViewType的进一步与业务结合的封装
具体已经支持的业务控件类型和视图控件类型,可以查看com.sangfor.pocket.uin.newway.UiItemTypes
public class UiItemTypes {
public static class ViewType {
public static final int VT_UNKNOWN = 0;
public static final int VT_LinearLayout_Vertical = 10;
...
}
public static class UiType {
public static final int UT_SELECT_NORMAL = 1;
public static final int UT_SINGLE_SELECT_CUSTM = 4;
public static final int UT_MULTIPLE_SELECT_CUSTM = 5;
...
}
}
由于整体框架遵循”业务控件“高于”视图控件“的一致性规则,因此,即便是一些不具备业务属性的基础视图控件,我们也不能直接使用其视图控件。而是需要定义其对应的业务控件去使用
1.1.1 业务控件UiType和视图控件ViewType转换器UiTypeMapToViewType
其实就是一个 对应的转换关系,将 UiType业务控件类型 转换为 viewType视图控件类型
public class UiTypeMapToViewType {
public int mapWithType(int uiType){
int type;
switch (uiType){
case UiItemTypes.UiType.UT_SELECT_NORMAL:
case UiItemTypes.UiType.UT_SELECT_TIME:
case UiItemTypes.UiType.UT_SINGLE_SELECT_CUSTM:
case UiItemTypes.UiType.UT_MULTIPLE_SELECT_CUSTM:
case UiItemTypes.UiType.UT_SINGLE_PERSON:
case UiItemTypes.UiType.UT_SINGLE_SELECT_CUSTM_BY_SALE_ORDER:
type = UiItemTypes.ViewType.VT_TextImageNormalForm;
break;
case UiItemTypes.UiType.UT_CLASS_TITLE:
//左边显示是表单
type = UiItemTypes.ViewType.VT_CLASS_TITLE;
break;
//...
}
}
}
1.2 BaseUiViewPool 基础控件池
上文我们已经说了,UiViewPool的主要目的就是
1.2.1 功能:生成视图控件View并返回
生成视图控件View并返回是UiViewPool的核心功能
它的核心实现就是借助 ViewMaker来实现的:
- 持有
Map<Integer, ViewMaker> pool = new HashMap<>();
视图控件类型ViewType 与对应 ViewMaker视图控件制造器 的Map - 借助
UiTypeMapToViewType
业务控件UiType和视图控件ViewType转换器,对UiType进行转换为viewtype - 使用viewtype对应的ViewMaker,new出真正的视图控件
public abstract class BaseUiViewPool implements UiViewPool {
protected Context context;
/**
* 视图控件类型ViewType 与对应 ViewMaker视图控件制造器 的Map
*/
protected Map<Integer, ViewMaker> pool = new HashMap<>();
public BaseUiViewPool(Context context) {
//上下文对象,用于创建视图控件
this.context = context;
//业务控件UiType 和 视图控件ViewType 转换器
map = new UiTypeMapToViewType();
//构建支持的 视图制造器列表
ViewMaker[] viewMakers = listViewMakers();
if(viewMakers != null && viewMakers.length > 0){
for(ViewMaker vm : viewMakers){
ViewMaker put = pool.put(vm.getViewType(), vm);
}
}
}
@Override
public View getView(int uiType, ViewGroup parent) {
ViewMaker viewMaker;
if(uiType == UiItemTypes.ViewType.VT_UNKNOWN){
viewMaker = UNKNOWN_VIEW_MAKER;
}else {
//1. 借助`UiTypeMapToViewType`业务控件UiType和视图控件ViewType转换器,对UiType进行转换为viewtype
//2. 获取viewtype对应的ViewMaker
viewMaker = pool.get(map.mapWithType(uiType));
if (viewMaker == null) {
if (BuildConfig.DEBUG) {
throw new IllegalStateException("Unsupported uiType [" + uiType + "]");
}
viewMaker = UNSUPPORTED_VIEW_MAKER;
}
}
//3. 使用viewtype对应的ViewMaker,new出真正的视图控件
return viewMaker.makeView(context, parent);
}
}
1.2.2 功能:初始化 持有视图控件ViewMakers 的 HashMap
在上个环节我们讲到了,借助Map<Integer, ViewMaker> pool = new HashMap<>();
视图控件类型ViewType 与对应 ViewMaker视图控件制造器 的Map,来获取对应的 ViewMaker
那么这个 HashMap 是怎么初始化的呢?
- 在我们的实际开发中,有一些基础控件池是全局都会使用的,针对这些我们需要提供一个集中处理器帮我们直接生成
- 同时,在具体的一些业务中,又会需要一些自定义的业务控件,那么我们的集中处理器也必须要有一定的配置功能
public abstract class BaseUiViewPool implements UiViewPool {
protected abstract ViewMaker[] listViewMakers();
}
具体的,我们现在有三个子类,我们分别看下他们的实现:
public class StandardViewPool extends BaseUiViewPool {
public StandardViewPool(Context context) {
super(context);
}
@Override
protected ViewMaker[] listViewMakers() {
return new ViewMaker[]{
new FlexiblePictureLayoutMaker(),
new ApprovalShowViewMaker(),
new RemovableOrangeClassifyTitleMaker(),
new AddButtonViewMaker(),
new InfoStatusBarViewMaker(),
new EmptyViewMaker()
};
}
}
public class FormViewPool extends BaseUiViewPool {
public FormViewPool(Context context) {
super(context);
}
@Override
protected ViewMaker[] listViewMakers() {
return new ViewMaker[]{
new TextEditableFormMaker(),
new TextImageNormalFormMaker(),
new LeftWrapContentTextImageNormalFormMaker(),
new FormTipsMaker(),
new IsolatedFormButtonMaker(),
new LeftRightTitleMaker(),
new PureEditableFormMaker()
};
}
}
public class JxcViewPool extends BaseUiViewPool {
public JxcViewPool(Context context) {
super(context);
}
@Override
protected ViewMaker[] listViewMakers() {
return new ViewMaker[]{
new StockCheckDetailsViewMaker(),
new StockCheckProductCreateViewMaker(),
new StockCheckProductShowViewMaker(),
new JxcProductItemViewMaker(),
};
}
}
1.2.3 功能:视图控件池的合并
需要注意的是,我们在上文列举的StandardViewPool
,FormViewPool
,JxcViewPool
都是直接继承BaseUiViewPool
这也就意味着他们支持的功能区域是各自独立的,那么我如何同时使用不同Pool呢?
/**
* 视图控件池的组合能力
* @param other
* @return
*/
public BaseUiViewPool merge(BaseUiViewPool other) {
pool.putAll(other.pool);
return this;
}
我们不使用继承结构,也是为了遵循开发中的”组合高于继承“的原则
1.3 ViewMaker 单个视图控件的制造器
根据当前指定的int 控件类型,生成对应的实际控件。
这是对**new 视图控件
**能力的一种抽象,借助该制造器赋予框架生成对应试图控件的能力
public interface ViewMaker {
/**
* 当前 制造器 对应的 viewtype视图控件类型
* 该值不能随意定义,必须集中管理为 {@link com.sangfor.pocket.uin.newway.UiItemTypes.ViewType}中自定义
* @return
*/
int getViewType();
/**
* 当前制造器 对应的 视图控件
* @param context new控件时需要的上下文
* @param parent 控件将被包含的parent group
* @return
*/
View makeView(Context context, ViewGroup parent);
}
1.3.1 目前支持的视图控件
目前支持的视图控件,主要包含以下样式(com.sangfor.pocket.uin.newway.UiItemTypes#ViewType
):
//框架自定义
public static final int VT_UNKNOWN = 0;
public static final int VT_STANDARD_GROUP = 6;
//android 原生View
public static final int VT_LinearLayout_Vertical = 10;
public static final int VT_EMPYT = 19;
//moa标准表单项
public static final int VT_TextEditableForm = 1;
public static final int VT_TextImageNormalForm = 2;
public static final int VT_FlexiblePictureLayout = 3;
public static final int VT_LEFT_WRAP_TEXT_IMAGE_NORMAL_FORM = 5;
public static final int VT_CLASS_TITLE = 7;
public static final int VT_ADD_BUTTON_VIEW = 8;//底部的 添加button
public static final int VT_PRODUCT_ITEM_VIEW = 9;//jxc的一个商品item,包含商品名称、批次号、数量、总价等
public static final int VT_FormTips = 11;
public static final int VT_IsolatedFormButton = 12;
public static final int VT_StockCheckDetailsView = 13;
public static final int VT_LeftRightTitle = 14;
public static final int VT_StockCheckProductCreateView = 15;
public static final int VT_InfoStatusBar = 16;
public static final int VT_StockCheckProductShowView = 17;
public static final int VT_PURE_EDITABLEFORM = 18;
//审批人
public static final int VT_APPROVAL_SHOW_VIEW = 4;
更直观的,我们简单的看两个实例:
public class TextImageNormalFormMaker implements ViewMaker {
@Override
public int getViewType() {
return UiItemTypes.ViewType.VT_TextImageNormalForm;
}
@Override
public View makeView(Context context, ViewGroup parent) {
return new TextImageNormalForm(context);
}
}
public class VerticalLinearLayoutMaker implements ViewMaker {
@Override
public int getViewType() {
return UiItemTypes.ViewType.VT_LinearLayout_Vertical;
}
@Override
public View makeView(Context context, ViewGroup parent) {
LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.VERTICAL);
return ll;
}
}
二、UIItem业务控件
2.1 UiItem接口
UIItem是对业务控件的一种抽象
在了解 UiItem之前,我们必须清晰的意识到,业务控件其本质还是一种视图控件。因此,视图控件所具备的一些能力,业务控件也会被具有和抽象出来
我们思考一个场景:选择客户,并据此进行分析
-
针对这是一个视图控件
- 标识它对应TextImageNormalForm视图控件
- 当前视图中的唯一标识?
- 它具备 渲染到实际布局中、从实际布局中移除、更新等生命周期
- 它可能有一定的 Margins、Visible、Clickable要求
- 他可能有一定的 上下分割线Divider的显示及缩进要求
- 一些点击或者长按事件的监听
- 感知自己父视图是谁的能力?
-
针对它具备一定的业务能力,也就是说和 CustmerVo相关
- 需要了解 使用CustmerVo 如何 进行界面上相关 字符串或者颜色的如何转换?----> UIValue
- UiItem 如何取出来 CustmerVo实例对象的引用 作为自己的展示vo?---->Getter
- UiItem被用户进行重选后,要将返回的新的CustmerVo实例对象 赋值到哪个引用上?---->Setter
- 需要一个生命周期回调,能够在适当时机处理这种转化的UI渲染?—>renderView
- UiItem对应的展示vo是否发生了变化?—>backup\isChanged
- 本身所具备的一些对点击或者长按的处理,譬如点击跳转到选择客户?—>onClick\onLongClick
- 一些检测规则,用于用户调用去校验是否满足要求?----> CheckInfo
- 对支持的ActivityResult的int Code的过滤? ----> Tag
-
UiItem的不保留活动的支持
- 本身是可以 序列化的?
- 本身不可以序列化,则需要一个生命周期函数,先提前自己new出来?HardSetting
2.1.1 业务能力的抽象
2.1.1.1 界面渲染值 UIValue
public interface UiValue<V> extends Parcelable, Cloneable{
/**
* 获取当前UiValue对应的界面渲染值
*/
String getStringValue();
/**
* 获取当前UiValue对应的VO实例对象
* 将会被{@link UiItem#extractFromGetter()} 赋值为 Getter中的引用
* 或者被更新操作赋值为一个新的引用
*
* 一般来说 UiValue的实现类中会持有一个 vo对象的引用:
* 1. **在初始化Getter过程中,该引用指向 业务代码中的原对象;**
* 2. **在更新后(譬如选择了一个新的供应商分类),该引用会指向一个新的对象**
*/
V getValue();
/**
* 判断UiValue是否差异,用于在 {@link UiItem#isChanged()}
*/
boolean isTheSame(UiValue other);
/**
* 用于UiValue的备份,用于在 {@link UiItem#backup()}
* 表示为界面初始值,将最终支持 {@link UiItem#isChanged()},以判断是否发生更新
*/
UiValue<V> copy();
}
我们来看一个供应商分类选择的实例:
public class JxcSelectSupplierclassUiValue extends BaseUiValue<SupplierClass> implements Parcelable {
private SupplierClass supplierClass;
public JxcSelectSupplierclassUiValue(SupplierClass sClass) {
this.supplierClass = sClass;
}
@Override
public String getStringValue() {
if (supplierClass != null && !TextUtils.isEmpty(supplierClass.classname)) {
return supplierClass.classname;
}
return "";
}
@Override
public SupplierClass getValue() {
return supplierClass;
}
@Override
public boolean isTheSame(UiValue other) {
if (other instanceof JxcSelectSupplierclassUiValue) {
SupplierClass otherSupplierClass = ((JxcSelectSupplierclassUiValue) other).supplierClass;
return supplierClass.classId == otherSupplierClass.classId && supplierClass.classname == otherSupplierClass.classname;
}
return false;
}
}
尤其需要注意一点,一般来说 UiValue的实现类中会持有一个 vo对象的引用:
- 在初始化Getter过程中,该引用指向 业务代码中的原对象;
- 在更新后(譬如选择了一个新的供应商分类),该引用会指向一个新的对象
2.1.1.2 VO转接器Getter|Setter
Getter|Setter是作用在类级别的,如果想针对某个VO操作,必须是传入某个Vo对象实例的内部成员变量,从而实现get|setter的响应都会针对当前Vo对象实例
public interface Getter<T> {
T get();
}
public interface Setter<T> {
void set(T data);
}
我们来看个例子:
public static class MyData {
public CustomerLineVo custm;
private Setter<CustomerLineVo> custmSetter = new Setter<CustomerLineVo>() {
@Override
public void set(CustomerLineVo data) {
custm = data;
}
};
private Getter<CustomerLineVo> custmGetter = new Getter<CustomerLineVo>() {
@Override
public CustomerLineVo get() {
return custm;
}
};
}
MyData myData = new MyData();
SingleSelectCustmUiItem selectCustmUiItem = new SingleSelectCustmUiItem(this);
selectCustmUiItem.setSetter(myData.custmSetter());
selectCustmUiItem.setGetter(myData.custmGetter);
2.1.1.3 UIValue、Getter和Setter的串联
在BaseUiItem中,我们可以观察到这种串联关系
从某种层次上,Getter、Setter的操作是高于 UIValue的。
这是由于,如果说模型”用户–>VO–>UIValue—>界面渲染“中UIValue割据了用户对View的直接操作,Getter|Setter相当于 框架和Vo打交道,而UiValue则是框架如何根据VO进行界面渲染和反向返回
- Getter
- void setGetter(Getter getter);
- void setGetConvertor(Convertor convertor);
- void extractFromGetter();
- Setter
- void setGetter(Getter getter);
- void setGetConvertor(Convertor convertor);
- void extractFromGetter();
- UiValue
- UiValue getValue();
- void setValue(UiValue value);
2.1.1.4 ”VO->UIValue–>界面渲染“的过程
我们先来看 ”VO->UIValue–>界面渲染“的过程,extractFromGetter()
:
@Override
public void extractFromGetter() {
if(getter != null) {
Object value = getter.get();
if (getConvertor != null) {
value = getConvertor.convert(value);
}
UiValue uiValue = getUiValueGenerator().generateUiValue(value);
setValue(uiValue);
}
}
@Override
public void setValue(UiValue value){
this.uiValue = value;
VT vt = mutexHolder.get();
if(vt != null){
updateValue(vt, uiValue);
}
}
可以看出基本遵循以下路线:
- 以
extractFromGetter()
作为入口 - 调用
Getter
,获取到VO对象实例 - 如果有转换器,则将Vo对象实例转换为指定类型的VO对象实例。此步骤,主要用于衔接Vo和UiValue的实际类型不统一
- 调用
UIValue构造器UiValueGenerator
构建UiValue - 调用
setValue(UiValue value)
- 内部可能触发更新更新界面逻辑
2.1.1.5 UiValueGenerator界面渲染值转换器
在BaseUiItem基本业务控件
提供了以下和UiValueGenerator相关的函数,基本可以看出就是以下默认的get|set函数
@Override
public void setUiValueGenerator(UiValueGenerator uiValueGenerator) {
this.uiValueGenerator = uiValueGenerator;
}
/**
* 提供一个 默认的 UiValue生成器
* @return
*/
protected UiValueGenerator provideDefaultUiValueGenerator(){
return null;
}
protected UiValueGenerator getUiValueGenerator(){
if(uiValueGenerator == null){
uiValueGenerator = provideDefaultUiValueGenerator();
}
return uiValueGenerator;
}
那么 UiValueGenerator 到底是什么呢?
它实际上承载着 ”VO->UIValue–>界面渲染“的过程中,”Vo–>UiValue”的过程“
不同的自定UiItem通过 重写provideDefaultUiValueGenerator()
实现 当前Item控制自己的转换
2.1.1.6 ”VO<–UIValue<–界面渲染“的过程
UIValue被更新后,getValue()所指向的引用将不再是原来Getter的对象地址,而是一个新的对象
譬如选了一个新的客户被赋值到 UIValue的一个自定义的引用里,因此需要我们调用setter去赋值
@Override
public UiValue getValue() {
return uiValue;
}
@Override
public void fillInSetter() {
if(setter != null) {
UiValue uiValue = getValue();
Object value = null;
if(uiValue != null) {
value = uiValue.getValue();
}
if (setConvertor != null) {
value = setConvertor.convert(value);
}
setter.set(value);
}
}
可以看出基本遵循以下路线:
- 以
fillInSetter()
作为入口 - 调用
getValue()
,获取到 界面渲染值。 - 通过界面渲染值拿到当前指向的的 vo实例
- 如果有转换器,则将Vo对象实例转换为指定类型的VO对象实例。此步骤,主要用于衔接Vo和UiValue的实际类型不统一
- 调用
Setter
的set函数给目标对象赋值
2.2 一个示例
public class JxcSelectSupplierClassUiItem extends TextImageNormalFormUiItem implements UiItemResultGetter {
public JxcSelectSupplierclassUiValue mUiValue;
public JxcSelectSupplierClassUiItem(Context context) {
super(context);
}
@Override
public void onClick() {
JxcSelectSupplierclassUiValue supplierClass = null;
if (getValue() != null && getValue() instanceof JxcSelectSupplierclassUiValue){
supplierClass = (JxcSelectSupplierclassUiValue)getValue();
}
SupplierIntentManager.intentToGetSupplierClass(getActivityStarter(), getRequestCode(), getRequestTag(0), supplierClass == null ? null : supplierClass.getValue());
}
@Override
public void getResult(Intent data, int operationTag) {
SupplierClass supplierClass = data.getParcelableExtra(SupplierIntentManager.KEY_JXC_SECECT_SUPPLIER_CLASS);
if (supplierClass != null) {
mUiValue = new JxcSelectSupplierclassUiValue(supplierClass.classId == -1 ? null : supplierClass);
setValue(mUiValue);
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(this.mUiValue, flags);
}
protected JxcSelectSupplierClassUiItem(Parcel in) {
super(in);
this.mUiValue = in.readParcelable(JxcSelectSupplierclassUiValue.class.getClassLoader());
}
public static final Creator<JxcSelectSupplierClassUiItem> CREATOR = new Creator<JxcSelectSupplierClassUiItem>() {
@Override
public JxcSelectSupplierClassUiItem createFromParcel(Parcel source) {
return new JxcSelectSupplierClassUiItem(source);
}
@Override
public JxcSelectSupplierClassUiItem[] newArray(int size) {
return new JxcSelectSupplierClassUiItem[size];
}
};
}
三、UiInteraction
UiInteraction是暴露给用户的操作手柄
从某种意义上,UiInteraction类似于RecyleView,回想下我们使用RecyleView时,仅需要配置datas、bindView和bindData就可以实现界面渲染
- 针对List items的操作
- 针对bindView的操作 也就是构建我们常规意义上的xml中各个view的过程
- 针对bindData的基础布局的vo渲染,也就是我们常规意义上的针对xml的一些View配置成我们vo的某些界面显示
- notifyItemSetChanged
- 针对Result响应的
- 针对判断界面内容是否改变
- 针对各个uiItem的vo合法性的检测
- 配置项和辅助utils
Item的Ui视图控件生成通过调用
UiInteraction#commit
或者UiInteraction#notifySetChanged()
触发,当然内部会对视图控件进行 属性和渲染值的初始化设定
Item的Ui属性由ITem自己控制,调用其UiItem#commitUiProps()
的函数触发其私有函数updateUiProps(VT view)
Item的UI渲染值通过UiInteraction#dumpOnItem()
—>item.extractFromGetter
—>item.setValue
—>item.updateValue
3.1 接口
public interface UiInteraction extends ActivityResultReceiver, SavableForm, ContextProvider, TimeConsumingOperationStatistic {
int MODE_INDEX_DEPENDING_ON_SRC = ListPendingOperationLogic.MODE_INDEX_DEPENDING_ON_SRC;
int MODE_INDEX_DYNAMIC = ListPendingOperationLogic.MODE_INDEX_DYNAMIC;
/***********************************针对List<UiItem> items***********************************/
/**
* 增
*/
//设置一个set操作, 需要调用commit来提交
UiInteraction setItems(List<UiItem> items);
//设置一个insert操作, 需要调用commit来提交
UiInteraction insertItem(int index, UiItem item);
//设置一个append操作, 需要调用commit来提交
UiInteraction appendItems(List<UiItem> items);
/**
* 删
*/
//设置一个remove操作, 需要调用commit来提交
UiInteraction removeItem(UiItem item);
//设置一个remove操作, 需要调用commit来提交
UiInteraction removeItem(int index);
/**
* 查:单个
*/
//通过一个用户定义的id 来搜寻 一个item,该item处在pending状态, 即commit方法未被调用, 会遍历树状结构,直到找到一个符合的为止
UiItem findItemInPendingStateByUserId(int userId);
//通过一个用户定义的id 来搜寻 一个item,会遍历树状结构,直到找到一个符合的为止
UiItem findItemByUserId(int userId);
//返回未经扩展的index位置的item
UiItem getItem(int index);
/**
* 查:全部
*/
//返回未经扩展的item 列表
List<UiItem> getItems();
//返回经过扩展的item列表(UiItemGroup被扩展成了子item )
List<UiItem> getExtendedItems();
/**
* 由于在树形结构中查找一个Uitem是要进行递归调用的,因此
* 1. 用户可以指定先把一些UiItem加入到缓存池中,以加快查询过程
* 2. 框架在查找UiItem时,也会将其主动添加到缓存池中
*/
//缓存一个item
void cacheItem(int userId, UiItem item);
//从缓存里获取item
UiItem getItemFromCache(int userId);
//先从缓存里查找,没有则从item树里找,找到更新到缓存
UiItem getAnItem(int userId);
/*****************************针对bindView的操作 也就是构建我们常规意义上的xml中各个view的过程************************/
/**
* 提交一系列操作
*/
void commit();
/**
* 退出操作
*/
void abort();
/**
* 全量更新UI:会导致全部初始化,类似与 setItems(newDatas).commit();
*/
void notifyItemSetChanged();
/***************针对bindData的基础布局的vo渲染,也就是我们常规意义上的针对xml的一些View配置成我们vo的某些界面显示*************/
/**
* 用item中的值填充实体, 需要先调用 item.setSetter 方法来进行绑定
* ps: 界面值 和 界面目标对象的属性 并不是实时对应关系,调用此方法,赋值到目标对象实例中的指定属性上
*/
void fillEntityUp();
/**
* 用实体中的字段值去填充界面item, 需要先调用 item.setGetter 方法来进行绑定
*/
void dumpOnItem();
void dumpOnItem(int userId);
/***********************************************针对Result响应的********************************************/
void setRequestCode(int requestCode);
void setActivityStarter(ActivityStarter activityStarter);
void setOnUiItemResultListener(OnUiItemResultListener listener);
/******************************************判断界面内容是否改变******************************************/
/**
* 备份界面内容
*/
void backup();
/**
* 备份userId对应的item
* @param userId
*/
void backup(int userId);
/**
* 判断界面内容是否改变
* @return
*/
boolean isChanged();
/******************************************针对各个uiItem的vo合法性的检测******************************************/
@Deprecated
CheckResult check();
CheckResult2 check2();
List<CheckResult2> checkAll();
/*************************************配置项和辅助utils****************************************/
/**
* 回填数据时,是否仅返回变动了的item
* @param onlyGetChangedValue
*/
void setOnlyGetChangedValue(boolean onlyGetChangedValue);
/**
* toast
* @param prompt
*/
void setPrompt(Prompt prompt);
// UiItem moveTo(int index);
/**
* 设置一个监听UiItem value值变化的监听器
* @param watcher
*/
void setUiItemValueWatcher(UiItemValueWatcher watcher);
void setOnUiItemClickListener(UiItem.OnUiItemClickListener listener);
/**
* 设置一系列未执行(commit) 的操作的下标的意义 默认为 MODE_INDEX_DEPENDING_ON_SRC
* @param mode
*/
void setIndexMode(int mode);
/*************************************针对不保留活动的**************************************/
UiInteraction autoRestore();
/**
* 当界面被销毁,重新进入,items被恢复 时调用此方法, 需要调用commit来提交
* @param items
* @return
*/
UiInteraction restoreItems(List<UiItem> items);
boolean isThereAnyPendingOperation();
void setTimeConsumingOperationWatcher(TimeConsumingOperationWatcher timeConsumingOperationWatcher);
编写注意
复用级别在UiItem,也就是说需要掌握UiItem及其相关类的创建方法
- TestTestNewwayOfUi
- TestNewwayOfUi
- TestUiItemList
- 对外接口必须加入注释,譬如ViewMaker