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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章