美文网首页
Android | Tangram动态页面之路(五)Tangra

Android | Tangram动态页面之路(五)Tangra

作者: 哈利迪ei | 来源:发表于2020-05-22 19:40 被阅读0次

    本系列文章主要介绍天猫团队开源的Tangram框架的使用心得和原理,由于Tangram底层基于vlayout,所以也会简单讲解,该系列将按以下大纲进行介绍:

    1. 需求背景

    2. Tangram和vlayout介绍

    3. Tangram的使用

    4. vlayout原理

    5. Tangram原理

    6. Tangram二次封装

    本文将对Tangram进行初步讲解。

    基于Tangram最新源码分析

    笔者Demo代码

    Tangram

    Tangram和vlayout介绍这篇文章提到过,Tangram通过解析json模板得到布局方式Card和具体视图Cell,然后将Card转换成对应的vlayoutLayoutHelper来进行测量和布局,如下,

    image

    官网的架构图如下,

    image

    Card转成LayoutHelper

    跟进TangramActivityengine.setData(data)

    //BaseTangramEngine.java
    void setData(T data) {
        //模板解析,json文件 -> JSONArray -> List<Card>
        List<C> cards = mDataParser.parseGroup(data, this);
        this.setData(cards);
    }
    
    void setData(List<C> data) {
        this.mGroupBasicAdapter.setData(data);
    }
    

    来到GroupBasicAdapter

    //GroupBasicAdapter.java
    void setData(List<L> cards, boolean silence) {
        //把cards转成vlayout的layoutHelpers
        setLayoutHelpers(transformCards(cards, mData, mCards));
        if (!silence)
            notifyDataSetChanged();
    }
    
    //cards指json模板中的多个布局方式card,
    //data指每个card里边的具体视图cell
    //rangeCards指一段管辖范围内所对应的布局方式card
    //假设第1个card对应ColumnLayoutHelper,有3个元素,则管辖范围是[0,2]
    //第2个card对应OnePlusNLayoutHelper,有4个元素,则管辖范围是[3,6],以此类推
    List<LayoutHelper> transformCards(List<L> cards, List<C> data,
                                      List<Pair<Range<Integer>, L>> rangeCards) {
        //data.size()初始值为0
        int lastPos = data.size();
        List<LayoutHelper> helpers = new ArrayList<>(cards.size());
        for (int i = 0, size = cards.size(); i < size; i++) {
            //遍历每个card
            L card = cards.get(i);
            //获取card的类型,如列布局container-fourColumn
            final String ctype = getCardStringType(card);
            //获取card内的cell数组
            List<C> items = getItems(card);
            //如果card里边没有cell,即没有视图,直接跳过
            if (items == null) {
                continue;
            }
            //记录每个card里边的多个cell
            data.addAll(items);
            int offset = lastPos;
            lastPos += items.size();
            //记录每一段管辖范围,和其对应的card
            rangeCards.add(Pair.create(Range.create(offset, lastPos), card));
            //获取card对应的LayoutHelper,暂不深究
            LayoutBinder<L> binder = mCardBinderResolver.create(ctype);
            LayoutHelper helper = binder.getHelper(ctype, card);
            if (helper != null) {
                //设置cell个数
                helper.setItemCount(items.size());
                helpers.add(helper);
            }
        }
        return helpers;
    }
    

    Card被转换成LayoutHelper

    image

    转换完成后,调用了notifyDataSetChanged,是如何显示到RecyclerView上的呢?

    RecyclerView展示

    跟进TangramActivityengine.bindView(recyclerView)

    //BaseTangramEngine.java
    void bindView(@NonNull final RecyclerView view) {
        this.mContentView = view;
        //设置VirtualLayoutManager
        this.mContentView.setLayoutManager(mLayoutManager);
        //设置性能监控,mLayoutManager负责监控cell的耗时
        mLayoutManager.setPerformanceMonitor(mPerformanceMonitor);
        if (mGroupBasicAdapter == null) {
            this.mGroupBasicAdapter = mAdapterBuilder.newAdapter(mContext, mLayoutManager, this);
            //设置性能监控,mGroupBasicAdapter负责监控card和cell的耗时
            mGroupBasicAdapter.setPerformanceMonitor(mPerformanceMonitor);
            //错误报告
            mGroupBasicAdapter.setErrorSupport(getService(InternalErrorSupport.class));
        }
        if (mContentView.getRecycledViewPool() != null) {
            //设置RecyclerView缓存池,InnerRecycledViewPool装饰了RecycledViewPool
            mContentView.setRecycledViewPool(new InnerRecycledViewPool(mContentView.getRecycledViewPool()));
        }
        //注册服务,暂不深究
        register(GroupBasicAdapter.class, mGroupBasicAdapter);
        register(RecyclerView.RecycledViewPool.class, mContentView.getRecycledViewPool());
        //设置适配器
        this.mContentView.setAdapter(mGroupBasicAdapter);
    }
    

    可见RecyclerView设置的适配器是GroupBasicAdapter,看下我们比较关心的几个方法,

    //GroupBasicAdapter.java
    
    int getItemViewType(int position) {
        C data = mData.get(position);
        //内部缓存了Map<String, Integer> mStrKeys
        //String就是cell名字如SingleImageView,Integer就是一系列从0开始递增的ViewType
        return getItemType(data);
    }
    

    官方Demo早期用了int来声明Cell,这样容易混乱,不利于在json模板里表意,现在改成了String来声明(为此还做了些兼容代码),建议直接使用String来注册,可参考Tangram的使用

    {
        "id": "banner1",
        "type": "container-oneColumn",
        "style": {
            "aspectRatio": 3.223
        },
        "items": [
            {
                "bizId":"item1",
                "type": 110,  //不要再使用int声明cell,建议使用唯一字符串如SingleImageView
                "msg": "info1"
            },
            {
                "bizId":"item2",
                "type": 110,  //不要再使用int声明cell,建议使用唯一字符串如SingleImageView
                "msg": "info2"
            }
        ]
    }
    

    然后看下onCreateViewHolderonBindViewHolder

    //GroupBasicAdapter.java
    
    BinderViewHolder<C, ? extends View> onCreateViewHolder(ViewGroup parent, int viewType) {
        //根据viewType得到cell名字
        String cellType = getCellTypeFromItemType(viewType);
        //大概是通过cellType帮我们创建对应的view,暂不深究
        ControlBinder<C, ? extends View> binder = mCompBinderResolver.create(cellType);
        //一个普通的ViewHolder,提供了bind方法
        BinderViewHolder binderViewHolder = createViewHolder(binder, mContext, parent);
        return binderViewHolder;
    }
    
    void onBindViewHolder(BinderViewHolder<C, ? extends View> holder, int position) {
        //获取cell
        C data = mData.get(position);
        //绑定cell
        holder.bind(data);
    }
    
    //省略调用链:
    //BinderViewHolder.bind -> BaseCellBinder.mountView -> MVHelper.mountView
    // -> MVHelper.postMountView -> ITangramViewLifeCycle.postBindView
    
    //回调到业务层,如TestView.java
    void postBindView(BaseCell cell) {
        //业务逻辑
        textView.setText("xxx");
    }
    

    至此,整个流程就跑通了。

    image

    参考文章

    image

    相关文章

      网友评论

          本文标题:Android | Tangram动态页面之路(五)Tangra

          本文链接:https://www.haomeiwen.com/subject/peucahtx.html