1、注册
WXSDKEngine#registerComponent
IFComponentHolder
ComponentCreator
SimpleComponentHolder -> IFComponentHolder
JavascriptInvokable
WXComponent
- WXText
WXComponentRegistry#registerComponent
AutoScanConfigRegister#preLoad(JavascriptInvokable)
WXComponentRegistry#registerNativeComponent
WXComponentRegistry#registerJSComponent
WXSDKManager#registerComponents
WXBridgeManager#registerComponents
WXBridgeManager#invokeRegisterComponents
WXBridge#execJS —> nativeExecJS
IFComponentHolder
public interface IFComponentHolder extends ComponentCreator,JavascriptInvokable {
/**
* 如果组件不是lazy加载模式,则优先加载此组件,默认是true
* 解析组件类中的{@link com.taobao.weex.annotation.Component}注解
* 接口触发时机在{@link WXComponentRegistry#registerNativeComponent}
*/
void loadIfNonLazy();
/**
* 获取组件注册过程中保存的自定义属性创建的相关方法
* 注册&生成入口流程参考 {@link JavascriptInvokable#getMethods()}
* @param name
* @return
*/
Invoker getPropertyInvoker(String name);
}
ComponentCreator
public interface ComponentCreator {
/**
* 通过type创建对应的wx组件对象,调用的入口参见
* {@link com.taobao.weex.ui.component.WXComponentFactory#newInstance(WXSDKInstance, WXVContainer, BasicComponentData)}
*/
WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException;
}
JavascriptInvokable
public interface JavascriptInvokable {
/**
* 首次调用的时机在{@link com.taobao.weex.ui.WXComponentRegistry#registerComponent}
* `registerInfo.put("methods",holder.getMethods());`
* 落地调用场景点{@link SimpleComponentHolder#getMethods(Class)} ()}
* 作用是将注册的组件中带有如下两个组件的方法存起来
* {@link com.taobao.weex.ui.component.WXComponentProp}
* (注册组件属性的方法)
* {@link com.taobao.weex.annotation.JSMethod}
* (注册js调用的native方法)
* 依次存放的实例(以 {@link SimpleComponentHolder} 为例,
* 具体要看 {@link com.taobao.weex.ui.IFComponentHolder}的实现方法):
* private Map<String, Invoker> mPropertyInvokers;
* private Map<String, Invoker> mMethodInvokers;
* {@link Invoker}是反射调用某个方法的接口,主要实现为{@link MethodInvoker}
* @return 返回匹配的方法名字的数组
*/
String[] getMethods();
/**
* 通过方法名字获取到在{@link #getMethods()}中保存的 mMethodInvokers
* @param name 方法名字
* @return 返回对应的 {@link MethodInvoker}
*/
Invoker getMethodInvoker(String name);
}
2、构建
由native js引擎解析完成后,开始以下调用链
-
WXBridge#callCreateBody
-
WXBridge#callCreateBody
-
action = new GraphicActionCreateBody()
this.mComponentType = componentType;
this.mStyle = style;
this.mAttributes = attributes;
this.mEvents = events;
this.mMargins = margins;
this.mPaddings = paddings;
this.mBorders = borders;
mComponentType对应WXBasicComponentType中的常量
mStyle 对应 js中
<style scoped>
中定义的style,除了margin , padding样式mEvents 对应 js中 标签的事件比如”@onclick”, “@appear”事件
mAttributes 对应js中 的属性,如”src”, “resize”等
basicComponentData = new BasicComponentData — 将上述的属性统统添加到bsd中
GraphicActionAbstractAddElement#createComponent — 创建WXComponent
- ```java if (basicComponentData != null) { //添加解析出的属性到此Component Data中 basicComponentData.addStyle(mStyle); basicComponentData.addAttr(mAttributes); basicComponentData.addEvent(mEvents); basicComponentData.addShorthand(mMargins, CSSShorthand.TYPE.MARGIN); basicComponentData.addShorthand(mPaddings, CSSShorthand.TYPE.PADDING); basicComponentData.addShorthand(mBorders, CSSShorthand.TYPE.BORDER); }
//通过basicComponentData实例化属性 WXComponent component = WXComponentFactory.newInstance(instance, parent, basicComponentData); //TODO 注册属性到WXRenderManager — 细节待摸清 WXSDKManager.getInstance().getWXRenderManager().registerComponent(getPageId(), getRef(), component);
- WXComponentFactory#newInstance
- ```java
/**
* 通过ComponentType去获取已经注册的IFComponentHolder
* 注册的位置见 {@link WXSDKEngine#register()}
*/
IFComponentHolder holder = WXComponentRegistry.getComponent(basicComponentData.mComponentType);
if (holder == null) { // 没有注册的情况
...
//没有注册的组件,默认当 CONTAINER,也就是一个 div标签 ->对应 WXFrameLayout
holder = WXComponentRegistry.getComponent(WXBasicComponentType.CONTAINER);
if (holder == null) { // 再挂了,就不管了
...
return null;
}
}
- WXRenderManager#registerComponent - ```java
/**
- 1、首先 {@link #mRenderContext}是一个线程安全的map,以instanceId为key,RenderContextImpl为value
- {@link #mRenderContext} 的初始化发生在 {@link WXRenderManager}的构造函数中,而 {@link WXRenderManager}
- 初始化是在 {@link WXSDKManager#WXSDKManager()} (Context)} 构造函数,并且是跟随父类都是唯一
- 2、{@link #mRenderContext} 中的值数据添加的调用链. WXSDKInstance是在初始化模板的时候定义的(及构建时),
- 实际的 {@link WXSDKInstance}存储在 {@link RenderContextImpl#RenderContextImpl}中的实例中,
- RenderContextImpl和instanceId 以kv的形式保存在mWXRenderManager中
- a.{@link WXSDKInstance#renderInternal(String, Script, Map, String, WXRenderStrategy)}
- b.{@link WXSDKManager#createInstance(WXSDKInstance, Script, Map, String)}
- c.{@link WXRenderManager#registerInstance(WXSDKInstance)}
- @param instanceId 每一个实例都有一个instanceId 实例ID
- @param ref 引用代表某个组件
@param comp 组件自身 */ public void registerComponent(String instanceId, String ref, WXComponent comp) { //已经在构建的时候保存了,一般不为null RenderContextImpl statement = mRenderContext.get(instanceId); if (statement != null) { //将组件comp和引用ref关联起来 statement.registerComponent(ref, comp); //理论上 WXSDKInstance 不为null if (null != statement.getInstance()){ //注册成功后,更新目前最大的组件数量 statement.getInstance().getApmForInstance().updateMaxStats(
WXInstanceApm.KEY_PAGE_STATS_MAX_COMPONENT_NUM, statement.getComponentCount()
); } } }
- component.addAnimationForElement(animationMap); --- 为组件添加动画 - ```java //组件的id和动画为map animations.add(new Pair<>(getRef(),animMap));
-
WXRenderManager#postGraphicAction(..,action) -> action = GraphicActionCreateBody
根据BasicGraphicAction的actionType来执行不同的处理方式
- ```java
if (action.mActionType == BasicGraphicAction.ActionTypeBatchEnd) {
postAllStashedGraphicAction(instanceId,action);
return;
} else if (action.mActionType == BasicGraphicAction.ActionTypeBatchBegin || this.mBatchActions.size() > 0 ) {
nativeBatchTimes ++ ;
if (nativeBatchTimes > MAX_DROP_FRAME_NATIVE_BATCH) {
postAllStashedGraphicAction(instanceId,action);
} else {
HashMap
item = new HashMap<>(1); item.put(sKeyAction, action); mBatchActions.add(item); return; } }
- ```java
if (action.mActionType == BasicGraphicAction.ActionTypeBatchEnd) {
postAllStashedGraphicAction(instanceId,action);
return;
} else if (action.mActionType == BasicGraphicAction.ActionTypeBatchBegin || this.mBatchActions.size() > 0 ) {
nativeBatchTimes ++ ;
if (nativeBatchTimes > MAX_DROP_FRAME_NATIVE_BATCH) {
postAllStashedGraphicAction(instanceId,action);
} else {
HashMap
//默认执行这里, 将action信息post到主线程中 mWXRenderHandler.post(instanceId, action);
- BasicGraphicAction.ActionTypeNormal 普通模式 - mWXRenderHandler.post(instanceId, action) -- post主线程执行runnable - BasicGraphicAction#run -- 经过此回调中转操作到executeAction - GraphicActionCreateBody#executeAction - ```java try { //创建组件的View component.createView(); //设置view显示的布局方式,以及绑定事件 component.applyLayoutAndEvent(component); //绑定相关的style属性,attr属性等 component.bindData(component); WXSDKInstance instance = getWXSDKIntance(); if (component instanceof WXScroller) { WXScroller scroller = (WXScroller) component; if (scroller.getInnerView() instanceof ScrollView) { //对scroll view 单独处理,添加监听等 instance.setRootScrollView((ScrollView) scroller.getInnerView()); } } //将创建的view添加到mRenderContainer,并且重新设置mRenderContainer的显示区域大小 instance.onRootCreated(component); //渲染策略 不是"一次添加",默认是 APPEND_ASYNC 就有对应的监听回调 mRenderListener.onViewCreated if (instance.getRenderStrategy() != WXRenderStrategy.APPEND_ONCE) { instance.onCreateFinish(); } } catch (Exception e) { WXLogUtils.e("create body failed.", e); }
- component.createView() -> WxComponent#createViewImpl - ```java
if (mContext != null) { //通过子类创建View mHost = initComponentHostView(mContext); … if (mHost != null) {
//创建的View没有id,则为其生成一个id
if(mHost.getId() == View.NO_ID)
mHost.setId(WXViewUtils.generateViewId());
if(TextUtils.isEmpty(mHost.getContentDescription()) && WXEnvironment.isApkDebugable()){
mHost.setContentDescription(getRef());
} ComponentObserver observer; if ((observer = getInstance().getComponentObserver()) != null) {
observer.onViewCreated(this, mHost);
} } onHostViewInitialized(mHost);//host view相关的初始化 } else { WXLogUtils.e(“createViewImpl”, “Context is null”); }
- WxComponent#onHostViewInitialized - ```java protected void onHostViewInitialized(T host) { //一般初始化的时候,mAnimationHolder都为null,在此不会被执行,有在onLayout改变的时候执行动画 if (mAnimationHolder != null) { //初始化后执行动画 mAnimationHolder.execute(mInstance, this); } //:active 事件由 onTouch来处理,用于更新style相关 setActiveTouchListener(); }
- component.applyLayoutAndEvent(component) - setLayout -- 处理view的显示方式 - ```java
setLayoutSize(component.getLayoutSize()); setLayoutPosition(component.getLayoutPosition()); setPaddings(component.getPadding()); setMargins(component.getMargin()); setBorders(component.getBorder());
- parseAnimation -- 解析transformOrigin(类同pivot)和transform(真实动画表达式)中的各个表达式,创建PropertyValuesHolder与之对应(WXAnimaitonBean负责做动画相关的事) - ```java for (final Pair<String, Map<String, Object>> pair : animations) { if (!TextUtils.isEmpty(pair.first)) { final WXAnimationBean animationBean = createAnimationBean(pair.first, pair.second); if (animationBean != null) { //创建动画执行的action GraphicActionAnimation action = new GraphicActionAnimation(getInstance(), getRef(), animationBean); //直接执行 action.executeAction(); } } }
- GraphicActionAnimation#executeAction -- 设置interceptor开始执行动画 - component.bindData(component) - ```java
//1、背景样式用BorderDrawable //2、反射调用由WXComponentProp注解的方法 updateStyles(component); //设置背景颜色,border颜色,radius,border厚度 updateAttrs(component); //额外的数据设置,现在只有WxText在用 updateExtra(component.getExtra());
- instance.onRootCreated(component) - ```java this.mRootComp = root; this.mRootComp.mDeepInComponentTree =1;//默认view的层级只有一层 //将创建的component添加到根view mRenderContainer.addView(root.getHostView()); //设置布局大小. layoutParams setSize(mRenderContainer.getWidth(),mRenderContainer.getHeight());
BasicGraphicAction.ActionTypeBatchBegin 批操作开始 — 未见使用场景
BasicGraphicAction.ActionTypeBatchEnd 批操作结束 — 未见使用场景
-