知識回顧
前面的文章分析了Tangram的結(jié)構(gòu)罕袋,以及組織數(shù)據(jù)和模塊的方式格遭。Tangram中一個(gè)列表頁面分成了多個(gè)card卡片,每個(gè)card卡片內(nèi)部的結(jié)構(gòu):head+多個(gè)cell組件+foot。Tangram對頁面的這種管理可以滿足不同的card奏司,布局樣式不同伸刃,比如card有g(shù)ridview樣式谎砾,一拖N樣式,輪播圖等等捧颅,達(dá)到了一個(gè)RecyclerView內(nèi)部不同的區(qū)域樣式不同景图,相對系統(tǒng)一個(gè)RecyclerView只能一種樣式的方案,布局更靈活碉哑。本篇文章將分析Tangram如何實(shí)現(xiàn)將下發(fā)的json數(shù)據(jù)顯示頁面的源碼實(shí)現(xiàn)挚币。
Tangram實(shí)現(xiàn)了什么
Tangram實(shí)現(xiàn)動態(tài)化構(gòu)建native頁面的框架。根據(jù)后臺配置的json數(shù)據(jù)扣典,實(shí)現(xiàn)json數(shù)據(jù)的解析妆毕,解析的數(shù)據(jù)包含布局信息和業(yè)務(wù)數(shù)據(jù)信息。RecyclerView根據(jù)json解析的數(shù)據(jù)模型中的布局信息贮尖,創(chuàng)建native view笛粘,以及利用數(shù)據(jù)模型的業(yè)務(wù)數(shù)據(jù)信息綁定view。而RecyclerView 的item可以實(shí)現(xiàn)多樣化的布局湿硝,它依賴的V-Layout實(shí)現(xiàn)薪前,V-Layout滿足了RecyclerView的item布局的多樣性。Tangram更像是一個(gè)解耦框架关斜,自定義不同的數(shù)據(jù)模型和view視圖示括。Tangram2.0還支持了新的功能VirtualView。
tangram內(nèi)部框架結(jié)構(gòu)
主要類說明:
- Tangram.Builder: 構(gòu)建數(shù)據(jù)模型和組件模型蚤吹。主要是產(chǎn)生兩個(gè)映射表例诀,數(shù)據(jù)模型的type-->數(shù)據(jù)模型的class,組件的type-->組件的class裁着。json數(shù)據(jù)的解析以及組件的構(gòu)建依賴這兩個(gè)映射表繁涂。
- TangramEngine:組織數(shù)據(jù)解析器解析數(shù)據(jù)模型,根據(jù)數(shù)據(jù)模型構(gòu)建布局管理器VirtualLayoutManager二驰,和數(shù)據(jù)適配器PojoGroupAdapter扔罪,以及將Recyclerview初始化,綁定適配器和布局管理器桶雀。
- DataParser:數(shù)據(jù)解析器矿酵,根據(jù)json對象的type字段唬复,實(shí)例化數(shù)據(jù)模型,依據(jù)mCardResolver和mcellResolver內(nèi)部的映射表全肮,利用反射實(shí)例化數(shù)據(jù)模型敞咧。
- VirtualLayoutManager:是RecyclerView的布局管理器,它根據(jù)itemView的布局類型辜腺,找到與itemView對應(yīng)的布局工具layoutHelper休建,由LayoutHelper完成布局計(jì)算。VirtualLayoutManager和LayoutHelper是V-Layout內(nèi)部的類评疗。
- PojoGroupBasicAdapter是RecyclerView的適配器测砂。
Tangram的工作流程
- 初始化組件庫,卡片庫百匆,以及數(shù)據(jù)模型砌些。Tangram采用的是集中式的管理組件,卡片以及數(shù)據(jù)模型加匈。這種管理方式優(yōu)點(diǎn)是管理集中存璃,缺點(diǎn)是擴(kuò)展時(shí)需要修改初始化代碼,容易出錯矩动∮星桑可以用分布式的方式替換,如注解的方式悲没,擴(kuò)展更便捷,不需要修改初始化邏輯男图。
- 構(gòu)建引擎示姿。
- 綁定RecyclerView。
- 解析json數(shù)據(jù)逊笆,轉(zhuǎn)換為卡片+組件的model栈戳,并綁定到布局框架,完成卡片渲染难裆。
Tangram源碼分析
初始化組件+卡片model子檀,view+布局庫
- 卡片model注冊到CardResolver,注冊的是type與card class的映射
- 組件model注冊到MVResolver乃戈,注冊的是type與cell class的映射褂痰。
- 布局注冊到BaseCardBinderResolver,注冊的是type與BaeLayoutBinder 實(shí)例對象的映射症虑。
- view注冊到BaseCellBinderResolver缩歪,注冊的是type與BaseCellBinder實(shí)例對象的映射,BaseCelBinder內(nèi)部創(chuàng)建view實(shí)例谍憔。
- 為什么view解析過程封裝了多層匪蝙?為了支持動態(tài)view--VirtualView
public static void installDefaultRegistry(@NonNull final DefaultResolverRegistry registry)
{
/*
* register built-in cards & mCells
*/
MVHelper mvHelper = new MVHelper(new MVResolver());
registry.setMVHelper(mvHelper);
// built-in mCells
registry.registerCell(TYPE_EXTENDED_VIEW_COMPACT, Card.PlaceholderCell.class,
SimpleEmptyView.class);
registry.registerCell(TYPE_EMPTY_VIEW_COMPACT, BaseCell.class, SimpleEmptyView.class);
//registry.registerCell(TYPE_SIMPLE_IMAGE_COMPACT, Cell.class, SimpleImgView.class);
registry.registerCell(TYPE_CAROUSEL_CELL_COMPACT, BannerView.class);
registry.registerCell(TYPE_CONTAINER_BANNER, BannerView.class);
registry.registerCell(TYPE_LINEAR_SCROLL_CELL_COMPACT, LinearScrollView.class);
registry.registerCell(TYPE_CONTAINER_SCROLL, LinearScrollView.class);
// built-in cards
registry.registerCard(TYPE_CAROUSEL_COMPACT, BannerCard.class);
registry.registerCard(TYPE_CONTAINER_BANNER, BannerCard.class);
registry.registerCard(TYPE_SINGLE_COLUMN_COMPACT, SingleColumnCard.class);
...
// extend cards
registry.registerCard(TYPE_FIX_COMPACT, FixCard.class);
registry.registerCard(TYPE_GRID_COMPACT, GridCard.class);
registry.registerCard(TYPE_LINEAR_COMPACT, LinearCard.class);
registry.registerCard(TYPE_X_COLUMN_COMPACT, ColumnCard.class);
}
綁定RecyclerView
public void bindView(@NonNull final RecyclerView view) {
//noinspection ConstantConditions
Preconditions.checkArgument(view != null, "view must not be null");
if (mContentView != null) {
mContentView.setAdapter(null);
mContentView.setLayoutManager(null);
}
this.mContentView = view;
this.mContentView.setLayoutManager(mLayoutManager);
mLayoutManager.setPerformanceMonitor(mPerformanceMonitor);
if (mGroupBasicAdapter == null) {
this.mGroupBasicAdapter = mAdapterBuilder.newAdapter(mContext, mLayoutManager, this);
mGroupBasicAdapter.setPerformanceMonitor(mPerformanceMonitor);
mGroupBasicAdapter.setErrorSupport(getService(InternalErrorSupport.class));
}
if (mContentView.getRecycledViewPool() != null) {
mContentView.setRecycledViewPool(new InnerRecycledViewPool(mContentView.getRecycledViewPool()));
}
- 給RecyclerView配置adapter
- 配置布局管理器
- 配置回收池主籍,回收池會在全局范圍共享,組件以及Recyclerview共享這個(gè)回收池逛球。
解析json數(shù)據(jù)千元,構(gòu)建card+cell 模型
//PojoDataParser.java
@Override
public List<Card> parseGroup(@NonNull JSONArray data, @NonNull final ServiceManager serviceManager) {
final CardResolver cardResolver = serviceManager.getService(CardResolver.class);
Preconditions.checkState(cardResolver != null, "Must register CardResolver into ServiceManager first");
final MVHelper cellResolver = serviceManager.getService(MVHelper.class);
Preconditions.checkState(cellResolver != null, "Must register CellResolver into ServiceManager first");
final int size = data.length();
final List<Card> result = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
JSONObject cardData = data.optJSONObject(i);
final Card card = parseSingleGroup(cardData, serviceManager);
if (card != null) {
if (card instanceof IDelegateCard) {
List<Card> cards = ((IDelegateCard) card).getCards(new CardResolver() {
@Override
public Card create(String type) {
Card c = cardResolver.create(type);
c.serviceManager = serviceManager;
c.id = card.id;
c.setStringType(type);
c.rowId = card.rowId;
return c;
}
});
for (Card c : cards) {
if (c.isValid()) {
result.add(c);
}
}
} else {
result.add(card);
}
}
}
cellResolver.resolver().setCards(result);
return result;
}
- 根據(jù)CardResolver構(gòu)建card實(shí)例
- 在card類內(nèi)部解析cell
- 根據(jù)MvResolver構(gòu)建cell實(shí)例
為adapter設(shè)置數(shù)據(jù)并構(gòu)建layoutHelper
// GroupBasicAdapter.java
public void setData(@Nullable List<L> cards, boolean silence) {
createSnapshot();
mCards.clear();
mData.clear();
if (cards != null && cards.size() != 0) {
mCards.ensureCapacity(cards.size());
setLayoutHelpers(transformCards(cards, mData, mCards));
} else {
setLayoutHelpers(Collections.<LayoutHelper>emptyList());
}
diffWithSnapshot();
if (!silence)
notifyDataSetChanged();
}
@NonNull
protected List<LayoutHelper> transformCards(@Nullable List<L> cards, final @NonNull List<C> data,
@NonNull List<Pair<Range<Integer>, L>> rangeCards) {
if (cards == null || cards.size() == 0) {
return new LinkedList<>();
}
int lastPos = data.size();
List<LayoutHelper> helpers = new ArrayList<>(cards.size());
for (int i = 0, size = cards.size(); i < size; i++) {
L card = cards.get(i);
if (card == null) continue;
final String ctype = getCardStringType(card);
List<C> items = getItems(card);
if (items == null) {
// skip card null
continue;
}
data.addAll(items);
// calculate offset to set ranges
int offset = lastPos;
lastPos += items.size();
// include [x, x) for empty range, upper are not included in range
rangeCards.add(Pair.create(Range.create(offset, lastPos), card));
// get layoutHelper for this card
LayoutBinder<L> binder = mCardBinderResolver.create(ctype);
LayoutHelper helper = binder.getHelper(ctype, card);
if (helper != null) {
helper.setItemCount(items.size());
helpers.add(helper);
}
}
return helpers;
}
//BaseCardBinderResolver.java
public BaseLayoutBinder create(String type) {
if (mDelegate.hasType(type)) {
return new BaseLayoutBinder();
}
return null;
}
// BaseLayoutBinder.java
public LayoutHelper getHelper(String type, Card data) {
if (data == null) return null;
return data.getLayoutHelper();
}
//
- layoutHelper的構(gòu)建過程:根據(jù)BaseCardBinderResolver的create方法,構(gòu)建BaseLayoutBinder颤绕,然后在BaseLayoutBinder的getHelper中調(diào)用形參card.getLayoutHelper獲得LayoutHelper诅炉,card與layoutHelper是一 一對應(yīng)的,不同type的card對應(yīng)的LayoutHelper不同屋厘。
Recyclerview渲染過程構(gòu)建view
//GroupBasicAdapter.java
@Override
public BinderViewHolder<C, ? extends View> onCreateViewHolder(ViewGroup parent, int viewType) {
String cellType = getCellTypeFromItemType(viewType);
ControlBinder<C, ? extends View> binder = mCompBinderResolver.create(cellType);
if (mPerformanceMonitor != null) {
mPerformanceMonitor.recordStart(PHASE_CREATE, cellType);
}
if (null == binder && null != errorSupport) {
Map<String, Object> infoMap = new HashMap<>();
infoMap.put("type", cellType);
infoMap.put("binderResolver", mCompBinderResolver.toString());
errorSupport.onError(InternalErrorSupport.ERROR_CREATE_VIEWHOLDER_NOT_FOUND_TYPE,
"Couldn't found component match certain type: " + cellType, infoMap);
}
BinderViewHolder binderViewHolder = createViewHolder(binder, mContext, parent);
if (mPerformanceMonitor != null) {
mPerformanceMonitor.recordEnd(PHASE_CREATE, cellType);
}
return binderViewHolder;
}
//PojoGroupBasicAdapter.java
@Override
public <V extends View> BinderViewHolder<BaseCell, V> createViewHolder(@NonNull ControlBinder<BaseCell, V> binder, @NonNull Context context, ViewGroup parent) {
V view = binder.createView(context, parent);
return new BinderViewHolder<>(view, binder);
}
//BaseCellBinder.java
public V createView(Context context, ViewGroup parent) {
V v;
if (viewHolderCreator != null) {
v = viewHolderCreator.create(context, parent);
} else if (mViewCreator != null) {
v = mViewCreator.create(context, parent);
} else {
v = (V) mMvHelper.getVafContext().getContainerService().getContainer(type, true);
}crea
if (v.getId() <= 0) {
v.setId(R.id.TANGRAM_VIEW_CONTAINER_ID);
}
return v;
}
//ViewCreator.java
public V create(@NonNull Context context, ViewGroup parent) {
try {
Constructor<V> constructor = mClz.getConstructor(Context.class);
view = constructor.newInstance(context);
return view;
} catch (InstantiationException e) {
handleException(e);
} catch (IllegalAccessException e) {
handleException(e);
} catch (InvocationTargetException e) {
handleException(e);
} catch (NoSuchMethodException e) {
handleException(e);
}
throw new RuntimeException("Failed to create View of class: " + mClz.getName());
}
- view的構(gòu)建過程:在BaseCellBinderResolver根據(jù)view的type涕烧,從其mSparseArray屬性中獲取BaseCellBinder實(shí)例調(diào)用BaseCellBinder.createView方法,createView方法內(nèi)部調(diào)用ViewCreator類的create方法汗洒,返回view實(shí)例议纯。或者createView在ViewHolderCreator或者M(jìn)VHelper中獲得view實(shí)例溢谤。
幾點(diǎn)疑惑
- layoutHelper是BaseLBaseL'LayoutBinder創(chuàng)建的瞻凤,為什么包裝了一層BaseCardBinderResolver?
在注冊的時(shí)候發(fā)現(xiàn)世杀,BaseCardBinderResolver并沒有對type和BaselayoutBinder映射阀参,BaseCardBinderResolver構(gòu)建的時(shí)候傳入一個(gè)代理CardResolver,這個(gè)代理在這里完成了兩件事情: - 容錯type類型,cardResolver不支持的類型瞻坝,BaseCrdBinderResolver 不處理蛛壳,丟棄掉。- 獲取支持的類型個(gè)數(shù)所刀。
由此可見BaseCardBinderResolver主要起到過濾type的作用衙荐,而BaseLayoutBinder主要構(gòu)建layoutHelper,這樣每個(gè)類的功能劃分明確浮创。
2.BaseCellBinderResolver與BaseCellBinder功能能否合并為一個(gè)類忧吟?
BaseCellBinderResolver中注冊type與BaseCellBinder的映射表,為了后面查詢使用,而BaseCellBinder的作用是構(gòu)建view實(shí)例,有三中方式:viewCreator斩披,viewHolderCreater以及mvHelper溜族。可見二者的功能劃分是很明確的垦沉,不能合并煌抒。