Android | Tangram動態頁面之路(五)Tangram原理

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本系列文章主要介紹天貓團隊開源的"},{"type":"link","attrs":{"href":"https://github.com/alibaba/Tangram-Android.git","title":""},"content":[{"type":"text","text":"Tangram"}]},{"type":"text","text":"框架的使用心得和原理,由於"},{"type":"codeinline","content":[{"type":"text","text":"Tangram"}]},{"type":"text","text":"底層基於"},{"type":"link","attrs":{"href":"https://github.com/alibaba/vlayout.git","title":""},"content":[{"type":"text","text":"vlayout"}]},{"type":"text","text":",所以也會簡單講解,該系列將按以下大綱進行介紹:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/e6c67e3f493e378edf74312e1","title":""},"content":[{"type":"text","text":"需求背景"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"2","normalizeStart":"2"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/de3f045f7390b848fa70f0c82","title":""},"content":[{"type":"text","text":"Tangram和vlayout介紹"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"3","normalizeStart":"3"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/b6b7c82140c3b6c804586e26a","title":""},"content":[{"type":"text","text":"Tangram的使用"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"4","normalizeStart":"4"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/5e575e7b16b9ffc6c3dfba69b","title":""},"content":[{"type":"text","text":"vlayout原理"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"5","normalizeStart":"5"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"Tangram原理"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"6","normalizeStart":"6"},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"Tangram二次封裝"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文將對"},{"type":"codeinline","content":[{"type":"text","text":"Tangram"}]},{"type":"text","text":"進行初步講解。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://github.com/alibaba/Tangram-Android/commit/64842305eeabd08b2dc8f1915da6a589665ceabc","title":""},"content":[{"type":"text","text":"基於Tangram最新源碼分析"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://github.com/holidayei/TangramDemo","title":""},"content":[{"type":"text","text":"筆者Demo代碼"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Tangram"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"link","attrs":{"href":"https://juejin.im/post/5eba9113f265da7bd442576f","title":""},"content":[{"type":"text","text":"Tangram和vlayout介紹"}]},{"type":"text","text":"這篇文章提到過,"},{"type":"codeinline","content":[{"type":"text","text":"Tangram"}]},{"type":"text","text":"通過解析json模板得到佈局方式"},{"type":"codeinline","content":[{"type":"text","text":"Card"}]},{"type":"text","text":"和具體視圖"},{"type":"codeinline","content":[{"type":"text","text":"Cell"}]},{"type":"text","text":",然後將"},{"type":"codeinline","content":[{"type":"text","text":"Card"}]},{"type":"text","text":"轉換成對應的"},{"type":"codeinline","content":[{"type":"text","text":"vlayout"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"LayoutHelper"}]},{"type":"text","text":"來進行測量和佈局,如下,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f2/f2520be9788ea3a344e0bf0e100e6749.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://tangram.pingguohe.net/docs/basic-concept/structure","title":""},"content":[{"type":"text","text":"官網的架構圖"}]},{"type":"text","text":"如下,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d2/d22e89f0375e15c1da6f2357d5e045ae.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Card轉成LayoutHelper"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"跟進"},{"type":"codeinline","content":[{"type":"text","text":"TangramActivity"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"engine.setData(data)"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//BaseTangramEngine.java\nvoid setData(T data) {\n //模板解析,json文件 -> JSONArray -> List\n List cards = mDataParser.parseGroup(data, this);\n this.setData(cards);\n}\n\nvoid setData(List data) {\n this.mGroupBasicAdapter.setData(data);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來到"},{"type":"codeinline","content":[{"type":"text","text":"GroupBasicAdapter"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//GroupBasicAdapter.java\nvoid setData(List cards, boolean silence) {\n //把cards轉成vlayout的layoutHelpers\n setLayoutHelpers(transformCards(cards, mData, mCards));\n if (!silence)\n notifyDataSetChanged();\n}\n\n//cards指json模板中的多個佈局方式card,\n//data指每個card裏邊的具體視圖cell\n//rangeCards指一段管轄範圍內所對應的佈局方式card\n//假設第1個card對應ColumnLayoutHelper,有3個元素,則管轄範圍是[0,2]\n//第2個card對應OnePlusNLayoutHelper,有4個元素,則管轄範圍是[3,6],以此類推\nList transformCards(List cards, List data,\n List, L>> rangeCards) {\n //data.size()初始值爲0\n int lastPos = data.size();\n List helpers = new ArrayList<>(cards.size());\n for (int i = 0, size = cards.size(); i < size; i++) {\n //遍歷每個card\n L card = cards.get(i);\n //獲取card的類型,如列布局container-fourColumn\n final String ctype = getCardStringType(card);\n //獲取card內的cell數組\n List items = getItems(card);\n //如果card裏邊沒有cell,即沒有視圖,直接跳過\n if (items == null) {\n continue;\n }\n //記錄每個card裏邊的多個cell\n data.addAll(items);\n int offset = lastPos;\n lastPos += items.size();\n //記錄每一段管轄範圍,和其對應的card\n rangeCards.add(Pair.create(Range.create(offset, lastPos), card));\n //獲取card對應的LayoutHelper,暫不深究\n LayoutBinder binder = mCardBinderResolver.create(ctype);\n LayoutHelper helper = binder.getHelper(ctype, card);\n if (helper != null) {\n //設置cell個數\n helper.setItemCount(items.size());\n helpers.add(helper);\n }\n }\n return helpers;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Card"}]},{"type":"text","text":"被轉換成"},{"type":"codeinline","content":[{"type":"text","text":"LayoutHelper"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ac/ace4c541f669babf0c2ca32e9245f7de.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"轉換完成後,調用了"},{"type":"codeinline","content":[{"type":"text","text":"notifyDataSetChanged"}]},{"type":"text","text":",是如何顯示到"},{"type":"codeinline","content":[{"type":"text","text":"RecyclerView"}]},{"type":"text","text":"上的呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"RecyclerView展示"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"跟進"},{"type":"codeinline","content":[{"type":"text","text":"TangramActivity"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"engine.bindView(recyclerView)"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//BaseTangramEngine.java\nvoid bindView(@NonNull final RecyclerView view) {\n this.mContentView = view;\n //設置VirtualLayoutManager\n this.mContentView.setLayoutManager(mLayoutManager);\n //設置性能監控,mLayoutManager負責監控cell的耗時\n mLayoutManager.setPerformanceMonitor(mPerformanceMonitor);\n if (mGroupBasicAdapter == null) {\n this.mGroupBasicAdapter = mAdapterBuilder.newAdapter(mContext, mLayoutManager, this);\n //設置性能監控,mGroupBasicAdapter負責監控card和cell的耗時\n mGroupBasicAdapter.setPerformanceMonitor(mPerformanceMonitor);\n //錯誤報告\n mGroupBasicAdapter.setErrorSupport(getService(InternalErrorSupport.class));\n }\n if (mContentView.getRecycledViewPool() != null) {\n //設置RecyclerView緩存池,InnerRecycledViewPool裝飾了RecycledViewPool\n mContentView.setRecycledViewPool(new InnerRecycledViewPool(mContentView.getRecycledViewPool()));\n }\n //註冊服務,暫不深究\n register(GroupBasicAdapter.class, mGroupBasicAdapter);\n register(RecyclerView.RecycledViewPool.class, mContentView.getRecycledViewPool());\n //設置適配器\n this.mContentView.setAdapter(mGroupBasicAdapter);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可見"},{"type":"codeinline","content":[{"type":"text","text":"RecyclerView"}]},{"type":"text","text":"設置的適配器是"},{"type":"codeinline","content":[{"type":"text","text":"GroupBasicAdapter"}]},{"type":"text","text":",看下我們比較關心的幾個方法,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//GroupBasicAdapter.java\n\nint getItemViewType(int position) {\n C data = mData.get(position);\n //內部緩存了Map mStrKeys\n //String就是cell名字如SingleImageView,Integer就是一系列從0開始遞增的ViewType\n return getItemType(data);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"官方Demo早期用了"},{"type":"codeinline","content":[{"type":"text","text":"int"}]},{"type":"text","text":"來聲明"},{"type":"codeinline","content":[{"type":"text","text":"Cell"}]},{"type":"text","text":",這樣容易混亂,不利於在json模板裏表意,現在改成了"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"來聲明(爲此還做了些兼容代碼),建議直接使用"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"來註冊,可參考"},{"type":"link","attrs":{"href":"https://juejin.im/post/5ebbe23ff265da7bfc40390c","title":""},"content":[{"type":"text","text":"Tangram的使用"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"json"},"content":[{"type":"text","text":"{\n \"id\": \"banner1\",\n \"type\": \"container-oneColumn\",\n \"style\": {\n \"aspectRatio\": 3.223\n },\n \"items\": [\n {\n \"bizId\":\"item1\",\n \"type\": 110, //不要再使用int聲明cell,建議使用唯一字符串如SingleImageView\n \"msg\": \"info1\"\n },\n {\n \"bizId\":\"item2\",\n \"type\": 110, //不要再使用int聲明cell,建議使用唯一字符串如SingleImageView\n \"msg\": \"info2\"\n }\n ]\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後看下"},{"type":"codeinline","content":[{"type":"text","text":"onCreateViewHolder"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"onBindViewHolder"}]},{"type":"text","text":","}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//GroupBasicAdapter.java\n\nBinderViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n //根據viewType得到cell名字\n String cellType = getCellTypeFromItemType(viewType);\n //大概是通過cellType幫我們創建對應的view,暫不深究\n ControlBinder binder = mCompBinderResolver.create(cellType);\n //一個普通的ViewHolder,提供了bind方法\n BinderViewHolder binderViewHolder = createViewHolder(binder, mContext, parent);\n return binderViewHolder;\n}\n\nvoid onBindViewHolder(BinderViewHolder holder, int position) {\n //獲取cell\n C data = mData.get(position);\n //綁定cell\n holder.bind(data);\n}\n\n//省略調用鏈:\n//BinderViewHolder.bind -> BaseCellBinder.mountView -> MVHelper.mountView\n// -> MVHelper.postMountView -> ITangramViewLifeCycle.postBindView\n\n//回調到業務層,如TestView.java\nvoid postBindView(BaseCell cell) {\n //業務邏輯\n textView.setText(\"xxx\");\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,整個流程就跑通了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"參考文章"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://tangram.pingguohe.net/docs/basic-concept/structure","title":""},"content":[{"type":"text","text":"Tangram官網-基礎架構"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a5/a59a19a54e6436e666d4a9b74fff8c29.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章