【HarmonyOS】PageSlider组件使用(二)Provider介绍-鸿蒙开发者社区-51CTO.COM

【HarmonyOS】PageSlider组件使用(二)Provider介绍 原创 精华

拓维信息Abin
发布于 2021-8-26 17:33
浏览
7收藏

一、简要概述

PageSliderProvider是为PageSlider组件提供用于管理页面视图的页面适配器。

PageSliderProvider类提供页面项管理功能,例如计算可用视图的数量和在指定位置创建组件。您需要继承并实现PageSliderProvider,以便在不同的页面上显示多个视图。

PageSliderProvider类的使用比较简单,但在复杂业务场景下使用时,需要做的工作比较多,而且这些工作都有重复性。所以在编写本章节案例的同时,我对PageSliderProvider进行了一下通用封装,并且把代码共享到了码云Gitee上,同时将封装的代码打包成har包,提交到了Maven中央仓库,供大家使用。

码云Gitee仓库地址

二、方法介绍

需要掌握的PageSliderProvider类方法不多,一般只需要重写下面四个方法即可为PageSlider提供Page数据支持。

方法名 作用
getCount() 获取可用Page页视图的数量。
createPageInContainer(ComponentContainer componentContainer, int position) 在指定位置创建Page页面。
destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) 销毁容器中的指定Page页面。
isPageMatchToObject(Component component, Object o) 视图是否关联指定对象。

PageSliderProvider类还提供了Page页面数据刷新需要用到的方法,这部分方法可以相互配合,达到精准更新Page页面数据。

方法名 作用
notifyDataChanged() 当页面数据集更改通知到PageSliderProvier刷新页面
getPageTitle(int position) 获取指定位置页面的标题。
getPageIndex(Object object) 获取容器中对象的索引。
startUpdate(ComponentContainer componentContainer) 获取可用Page页视图的数量。
onUpdateFinished(ComponentContainer componentContainer) 在指定位置创建Page页面。
addDataSubscriber(DataSetSubscriber subscriber) 从当前PageSliderProvider添加订阅服务。
removeDataSubscriber(DataSetSubscriber subscriber) 从当前PageSliderProvider移除订阅服务。

三、封装解析

PageSliderProvider是一个abstract抽象类,每次使用此类的时候都需要继承它,并重写相应的抽象方法。这种重复的工作,写多了,既繁琐,又浪费时间,降低开发效率。所以秉着高效易用的目的,先对PageSliderProvider进行一定封装。

数据源的封装。在常规业务开发模式中,为PageSliderProvider提供页面元数据是最基础的工作,一般都是将一个复杂的Object对象实例集合加入到一个List列表中。考虑数据的通用性,这里我们也将采用泛型来封装PageSliderProvider类。

public abstract class BasePageSliderProvider<M> extends PageSliderProvider {

    //页面加载数据源
    private final List<M> mPageSliderSourceData;

    //构造函数初始化列表集合
    public BasePageSliderProvider() {
        this.mPageSliderSourceData = new ArrayList<>();
    }
	
    /**
     * 对外提供清除数据源的操作方法,
     *
     * 后续需要根据业务自行判断是否需要调用notifyDataChanged()方法
     */
    public final void clearSourceData() {
        mPageSliderSourceData.clear();
    }

    /**
     * 对外提供设置/重置数据源的操作方法,
     *
     * 后续需要根据业务自行判断是否需要调用notifyDataChanged()方法
     * @param data
     */
    public final void setSourceData(List<M> data) {
        if (!data.isEmpty()) {
            mPageSliderSourceData.clear();
            mPageSliderSourceData.addAll(data);
        }
    }

    /**
     * 对外追加数据源的操作方法,可能在加载更多数据的时候有用。
     *
     * 后续需要根据业务自行判断是否需要调用notifyDataChanged()方法
     * @param data
     */
    public final void appendSourceData(List<M> data) {
        if (!data.isEmpty()) {
            mPageSliderSourceData.addAll(data);
        }
    }

    /**
     * 对外提供删除指定数据源的操作方法,
     *
     * 后续需要根据业务自行判断是否需要调用notifyDataChanged()方法
     * @param data
     */
    public final void removeSourceData(M data) {
        if (data != null) {
            mPageSliderSourceData.remove(data);
        }
    }

    /**
     * 对外提供获取指定位置数据的操作方法
     * @param position
     * @return
     */
    public final M getItem(int position) {
        return mPageSliderSourceData.get(position);
    }

    /**
     * 并使用final修饰,防止子类继承重写,导致出现问题。
     * @return
     */
    @Override
    public final int getCount() {
        return mPageSliderSourceData.size();
    }
    
}    

在重写PageSliderProvider类的getCount()抽象方法时,对此方法使用了final关键字修饰,目的是为了防止子类继承重写,导致出现问题。

页面视图组件的封装。页面视图组件是嵌入式设备应用开发中最需要关心的一件事情,嵌入式设备因内存资源是有限的的,而页面视图组件占用内存资源都还比较大,处理不好,甚至影响应用的流畅性和稳定性。所以在对页面视图组件封装时,需要考虑视图组件的快速创建和及时回收,防止内存泄露/溢出等问题。

在以往的应用开发经验中,ViewHolder绑定视图组件是一种非常高效解决视图组件回收复再利用的好模式。本次我们也使用这种ViewHolder模式来封装页面视图组件,并在PageSliderProvider类中进行简单的组件回收和再利用处理。

创建一个PageViewHolder类,用于绑定页面视图组件。在PageViewHolder类中进行简单的视图组件封装,业务开发中继承本类,去实现更多跟复杂的组件操作。

public abstract class PageViewHolder {

    protected final Component component;

    public PageViewHolder(Component component) {
        this.component = component;
    }

    /**
     * 返回绑定的视图组件
     * @return
     */
    public final Component getComponent() {
        return component;
    }
}

具体的业务开发中,使用的ViewHolder肯定是PageViewHolder的子类,是无法确定具体的实例对象类型的。所以在重写PageSliderProvider类的时候,我们也需要采用泛型来达到通用性。

页面视图组件的回收和再利用,常规简单操作我们都是使用列表或者队列进行存储,模拟回收站功能。在创建组件和销毁组件的方法中进行再利用和回收操作,已达到可以反复循环利用的目的,减少页面视图组件的多次创建带来的性能消耗。

public abstract class BasePageSliderProvider<M, VH extends PageViewHolder> extends PageSliderProvider {

    //页面PageViewHolder缓存,主要保存当前处于活跃状态的PageViewHolder对象
    private final HashMap<Integer, VH> mPageSliderComponentCache;

    //页面PageViewHolder回收站
    private final Queue<VH> mPageSliderComponentRecyclers;

    
    public BasePageSliderProvider() {
        this.mPageSliderComponentCache = new HashMap<>();
        this.mPageSliderComponentRecyclers = new LinkedBlockingQueue<>();
    }

    /**
     * 对外提供获取指定位置PageViewHoder对象的方法
     * @param position
     * @return
     */
    public final VH getPageViewHolder(int position) {
        return mPageSliderComponentCache.get(position);
    }

    @Override
    public Object createPageInContainer(ComponentContainer componentContainer, int index) {
        if (componentContainer == null || index >= getCount()) {
            return Optional.empty();
        }

        //从PageViewHolder回收站中获取对象,如果没有,创建新的PageViewHolder实例
        VH pageViewHolder = mPageSliderComponentRecyclers.poll();
        if (pageViewHolder == null) {
            pageViewHolder = onCreatePageViewHolder(componentContainer, index);
        }

        onBindPageViewHolder(pageViewHolder, index);
        componentContainer.addComponent(pageViewHolder.getComponent());
        //添加到缓存中
        mPageSliderComponentCache.put(index, pageViewHolder);

        return pageViewHolder;
    }

    @Override
    public void destroyPageFromContainer(ComponentContainer componentContainer, int index, Object object) {
        if (componentContainer == null || index >= getCount()) {
            return;
        }

        if (object instanceof PageViewHolder) {
            componentContainer.removeComponent(((PageViewHolder) object).getComponent());
            mPageSliderComponentCache.remove(index);
            //回收已经被销毁的PageViewHolder
            mPageSliderComponentRecyclers.offer((VH) object);
        }
    }

    @Override
    public boolean isPageMatchToObject(Component component, Object object) {
        if (object instanceof PageViewHolder) {
            return component == ((PageViewHolder) object).getComponent();
        }
        return component == object;
    }

    /**
     * 创建并返回一个PageViewHolder对象
     * @param componentContainer
     * @param position
     * @return
     */
    protected abstract VH onCreatePageViewHolder(ComponentContainer componentContainer, int position);

    /**
     * 为指定位置的PageViewHolder对象绑定数据
     * @param holder
     * @param position
     */
    protected abstract void onBindPageViewHolder(VH holder, int position);
    
}

四、应用实战

经过一系列的简单封装,PageSliderProvider类使用起来就简单了。我们就不需要再去为页面数据和组件的绑定,重复的去造轮子。直接从BasePageSliderProvider类继承,重写onCreatePageViewHolder和onBindPageViewHolder两个方法,直接绑定数据即可完成PageSlider组件的数据和页面组件的提供。

  1. 在工程layout目录下的创建Page页面布局文件。比如:component_page.xml

    <?xml version="1.0" encoding="utf-8"?>
    <DependentLayout
        xmlns:ohos="http://schemas.huawei.com/res/ohos"
        ohos:height="match_parent"
        ohos:width="match_parent">
    
        <Text
            ohos:id="$+id:text_component"
            ohos:height="match_parent"
            ohos:width="match_parent"
            ohos:text_size="32fp"
            ohos:text_font="sans-serif-medium"
            ohos:text_weight="800"
            ohos:text_color="#ffffff"
            ohos:text_alignment="center"/>
    
    </DependentLayout>
    
  2. 继承PageViewHolder类,绑定Page页面布局组件。比如:CasePageViewHolder

    private static class CasePageViewHolder extends PageViewHolder {
    
        private Text mTextCom;
    
        public CasePageViewHolder(Component component) {
            super(component);
            mTextCom = (Text) component.findComponentById(ResourceTable.Id_text_component);
        }
    
        public void setText(String text) {
            mTextCom.setText(text);
        }
    
        public void setBackground(RgbColor color) {
            ShapeElement element = new ShapeElement();
            element.setShape(ShapeElement.RECTANGLE);
            element.setRgbColor(color);
            mTextCom.setBackground(element);
        }
    }
    
  3. 继承BasePageSliderProvider类,绑定Page页面数据源和PageViewHolder。

    private static class CasePageSliderProvider extends BasePageSliderProvider<PageInfo, CasePageViewHolder> {
    
        @Override
        protected CasePageViewHolder onCreatePageViewHolder(ComponentContainer componentContainer, int position) {
            LayoutScatter layoutScatter = LayoutScatter.getInstance(componentContainer.getContext());
            Component component = layoutScatter.parse(ResourceTable.Layout_component_page, componentContainer, false);
            return new CasePageViewHolder(component);
        }
    
        @Override
        protected void onBindPageViewHolder(CasePageViewHolder holder, int position) {
            PageInfo pageInfo = getItem(position);
            holder.setText(pageInfo.getContent());
            holder.setBackground(pageInfo.getColor());
        }
    }
    
  4. 初始Page页面元数据和PageSlider组件,并将PageSliderProvider对象绑定到PageSlider组件中。

    public class MainAbilitySlice extends AbilitySlice {
    
        private PageSlider mPageSlider;
        private CasePageSliderProvider mPageSliderProvider;
    
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setUIContent(ResourceTable.Layout_ability_main);
            mPageSlider = (PageSlider) findComponentById(ResourceTable.Id_page_slider_component);
    
            mPageSliderProvider = new CasePageSliderProvider();
            mPageSliderProvider.setSourceData(createAndInitPageData());
            mPageSlider.setProvider(mPageSliderProvider);
        }
    
        //初始化Page页面元数据
        private List<PageInfo> createAndInitPageData(){
            List<PageInfo> initData = new ArrayList<>();
            for (int i = 0; i < 15; i++) {
                PageInfo pageInfo = new PageInfo();
                char tempChar = (char) (new Random().nextInt(26) + 65);
                pageInfo.setContent("Case " + String.valueOf(tempChar));
                pageInfo.setColor(new RgbColor(
                        new Random().nextInt(255),
                        new Random().nextInt(255),
                        new Random().nextInt(255)));
                initData.add(pageInfo);
            }
            return initData;
        }
       
        private static class PageInfo {
    
            private String content;
            private RgbColor color;
    
            public String getContent() {
                return content;
            }
    
            public void setContent(String content) {
                this.content = content;
            }
    
            public RgbColor getColor() {
                return color;
            }
    
            public void setColor(RgbColor color) {
                this.color = color;
            }
        }
    }
    

五、总结

这里只是简单的对PageSliderProvider类进行了一下封装试用,并将代码提交到了码云Gitee仓库,并进行了Maven中央仓库管理。PageSliderProvider类其实还可以进行更多功能改造,封装的更加高效易用,如果有意向,可以直接在码云Gitee仓库进行代码共享哦。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-9-10 08:53:22修改
8
收藏 7
回复
举报
回复
    相关推荐