在上一篇文章《深刻Weex系列(四)之Module組件源碼解析》中咱們結合源碼學習了Module的註冊、調用、回調等流程,而且分析一個Weex自帶Module的實現。html
那麼本篇文章咱們開始分析Weex的另外一個重要組件Component,關於Component的註冊、調用等分析本文爲你娓娓道來。android
在《Android 擴展》中咱們能夠看到Component的定位:git
Component 擴展 實現特別功能的Native控件。例如:RichTextview,RefreshListview 等。github
你們知道Android的四大組件中用戶惟一有感知的就是Activity,而在Weex的這些組件中用戶惟一有感知的也就是Component。實際上它就是Weex裏的Widget,好比咱們在WeexList中開發的Js代碼中寫的那些控件,最終在Native都是一個個的Component。apache
對於普通的界面開發,咱們通常不會見到Component的蹤影,由於Weex已經提供了一套基礎的Component組件與基礎Html標籤的對應,例如基礎Component組件的註冊:bash
registerComponent(
new SimpleComponentHolder(
WXImage.class,
new WXImage.Ceator()
),false,WXBasicComponentType.IMAGE,WXBasicComponentType.IMG
);
registerComponent(WXBasicComponentType.CELL, WXCell.class, true);
registerComponent(WXBasicComponentType.INDICATOR, WXIndicator.class, true);
registerComponent(WXBasicComponentType.VIDEO, WXVideo.class, false);
registerComponent(WXBasicComponentType.INPUT, WXInput.class, false);
registerComponent(WXBasicComponentType.TEXTAREA, Textarea.class,false);
registerComponent(WXBasicComponentType.SWITCH, WXSwitch.class, false);
複製代碼
項目中總有些效果是內置的Component沒法實現的,**此時咱們就要像自定義控件同樣自定義Component,具體實例能夠參考WeexList中的CircleImageView與RefreshView兩個自定義Component。**下面主要說下注意事項:微信
@WXComponentProp(name = "setSrc")
public void setImage(String url) {
}
複製代碼
WXSDKEngine.registerComponent("circleImageView", CircleImageView.class);
複製代碼
<circleImageView :setSrc="item.bphoto" style="width:100;height:100"></circleImageView>
複製代碼
注意這個 :setSrc 就是上面註解上的name;weex
Component的註冊和Module很像,你們從時序圖上能夠看出有幾個很熟悉的類;Component一樣分爲本地註冊與Js註冊;ide
本地註冊源碼分析
Js註冊
以自定義Component的方法調用爲例,Component的調用相對比較複雜,咱們拆分紅兩步來看,調用準備和調用執行;
調用準備說明:
@Override
public void postRenderTask(RenderAction action) {
mNormalTasks.add(new RenderActionTask(action, mWXRenderManager.getRenderContext(mInstanceId)));
mDirty = true;
}
複製代碼
調用執行說明:
經過上述對Component註冊、調用等的源碼分析,咱們能夠看到Component相比較Module仍是比較複雜的。若是你們仔細跟Component源碼的話會發現一個問題:第一步調用準備和第二步調用執行是如何串起來的?
在第一步調用準備結束以後,只是將任務加到了mNormalTasks保存,並無任何執行任務的代碼,那第二步調用執行是如何被調用的? 這個問題也困擾了我若干分鐘。
下面說說我對這塊的探索:Weex的繪製邏輯和Android原生很相似,Android會每隔16毫秒發出一次VSYNC信號觸發對UI進行渲染,而Weex也會每隔16毫秒發出一個消息觸發繪製,具體的邏輯在WXDomHandler中的WX_DOM_BATCH類型消息中;
public class WXDomHandler implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
if (!mHasBatch) {
mHasBatch = true;
mWXDomManager.sendEmptyMessageDelayed(WXDomHandler.MsgType.WX_DOM_BATCH, DELAY_TIME);
}
case MsgType.WX_DOM_BATCH:
mWXDomManager.batch();
mHasBatch = false;
break;
}
}
複製代碼
從mWXDomManager.batch()開始後續的邏輯就串起來了,DOMActionContextImpl中的consumeRenderTasks方法對RenderTask進行消費也就是第一步調用準備Task的執行;
Weex對經常使用控件都進行了封裝具體在com.taobao.weex.ui.component下能夠找到,一些文檔上沒寫的屬性之類的能夠在源碼中查找,畢竟源碼面前,了無祕密。
下面咱們簡單看一個經常使用的控件:列表控件,Weex裏內置了WXListComponent來支持列表控件;
@Component(lazyload = false)
public class WXListComponent extends BasicListComponent<BounceRecyclerView> {
......
@WXComponentProp(name = Constants.Name.COLUMN_GAP)
public void setColumnGap(float columnGap) throws InterruptedException {
if(mRecyclerDom != null && mRecyclerDom.getColumnGap() != mColumnGap) {
markComponentUsable();
updateRecyclerAttr();
WXRecyclerView wxRecyclerView = getHostView().getInnerView();
wxRecyclerView.initView(getContext(), mLayoutType, mColumnCount, mColumnGap, getOrientation());
}
}
......
}
複製代碼
能夠看出:
對於咱們自定義的Component均可以參照這個思路,具體實例能夠參考WeexList。
歡迎持續關注Weex源碼分析項目:Weex-Analysis-Project
歡迎關注微信公衆號:按期分享Java、Android乾貨!