27.HarmonyOS App(JAVA)可复用列表项的ListContainer

可复用列表项的ListContainer

简短的列表可以通过定向布局实现,但是如果列表项非常多,则使用定向布局就不再合适。如需要创建50个列表项的列表,那么用定向布局实现至少需要创建50个以上的组件了。然而,限于设备屏幕大小的限制,绝大多数组件不会显示在屏幕上,却会占据大量的内存资源,甚至导致应用"闪退"。

与其他移动开发技术一样,鸿蒙操作系统也提供了可复用列表项的列表组件ListContainer。

注意: 在Android和IOS系统中,均提供了与ListContainer类似的可复用列表项的列表组件。在安卓系统中,这种组件被称为RecyclerView; 在IOS系统中,这种组件被称为UITableView。

ListContainer继承于ComponentContainer,属于布局的一种。

在ListContainer中,每个列表项都是一个组件或者子布局,即列表项组件。不过,ListContainer非常"吝啬"。

例如,利用ListContainer实现具有50个列表项的列表,ListContainer绝对不会实实在在地创建50个组件,而是仅创建屏幕当前能够显示的列表项组件。

例如,当前的设备屏幕只能够显示六个列表项,那么ListContainer只创建六个列表项组件。当用户上下滑动到其他的列表项时,被滑出去的列表项组件会被新的列表项复用,重新更换数据后再次进入用户的视野,如图1所示。

在图1中,Item 1组件被滑出列表,随后被ListContainer"换装"填入新的数据后再次从列表底部重新进入ListContainer。Item 1组件和Item 7组件实际上是1个组件,组件还是原来的组件,只不过数据已经不是原来的数据了。这种按需创建组件的思想对于应用程序能够流畅稳定地运行非常重要。这么说来,ListContainer就像一个掌管着系统资源的大臣,时时刻刻打着精细的算盘,用最少的内存资源来干更多事情。

那么,我们应该如何来使用ListContainer呢? 实际上,ListContainer已经封装好复用列表项的机制了,不需要开发者过多操心。作为开发者,只需为ListContainer提供需要显示的列表项所需要的数据和组件就可以了,而这项工作就全权交给RecycleItemProvider类完成了。RecycleItemProvider是一个抽象类,开发者在使用它之前需要至少实现以下4种方法。

(1) getCount(): 提供列表项数量。

(2) getItem(int i): 提供当前列表项的数据。

(3) getItemId(int i): 提供当前列表项ID。

(4) getComponent(int id,Component cpt,ComponentContainer ctn): 创建组件与数据绑定,即创建属于这个列表项的组件,然后绑定该列表项数据。在这种方法中,id表示这个列表项ID,cpt对象为上一次这个列表项的组件对象。作为开发者可以直接复用这个组件对象,当然也可以创建一个新的组件对象。ctn是cpt组件的父布局对象。

ListContainer和RecycleItemProvider的具体使用方法。

首先,通过布局文件(recycle_item.xml)创建列表项的用户界面,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical">
    <Text
        ohos:id="$+id:item_text"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:margin="5vp"
        ohos:text_size="15fp"
        ohos:text_alignment="center"/>


</DirectionalLayout>

这个列表项非常简单,仅仅显示了一个文本组件,用于显示列表项数据,但是,这个用户界面与之前介绍的AbilitySlice界面不同,这个列表项界面仅仅显示在屏幕的某一个部位,因此不能使用之前的setUIContent方法了。

此时,需要LayoutScatter类来解析这个布局文件,LayoutScatter并不能直接被初始化,需要通过其getInstance(Context context)方法获取,其中content为当前的上下文对象。获取LayoutScatter 对象后,通过其parse(int xmlId,ComponentContainer root,boolean attachToRoot)方法即可解析所需要的XML布局文件,并且转换为组件对象。在parse方法中,xmlId表示需要解析的布局资源ID。当attachToRoot参数为true时,可以将解析出来的组件对象自动添加到root布局中,但是,在绝大多数情况下并不需要这么做,此时传递root参数为null,传递attachToRoot参数为false即可。

ability_main.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <ListContainer
        ohos:id="$+id:list_container"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:orientation="vertical"
        />

</DirectionalLayout>

MainAbilitySlice.java

package com.example.myapplication.slice;

import com.example.myapplication.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;

import java.util.ArrayList;
import java.util.List;

public class MainAbilitySlice extends AbilitySlice {
    private ListContainer mListContainer;
    private List<Integer> mNumbers;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        mNumbers = new ArrayList<>();
        for(int i =0;i<50;i++)
        {
            mNumbers.add(i+1);
        }
        //获取ListContainer对象
        mListContainer = (ListContainer) findComponentById(ResourceTable.Id_list_container);
        //为ListContainer对象设置RecycleItemProvider
        mListContainer.setItemProvider(new RecycleItemProvider() {
            @Override
            public int getCount() {
                return mNumbers.size(); //列表项数
            }

            @Override
            public Object getItem(int i) { //当前列表项数据
                return mNumbers.get(i);
            }

            @Override
            public long getItemId(int i) {
                return i; //当前列表项ID
            }

            @Override
            public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
                //列表项用户界面,如果可复用之前的界面,则直接复用
                DirectionalLayout layout = (DirectionalLayout) component;
                if(layout == null)
                {
                    //如果之间的界面为空,则创建新的列表项用户界面
                    layout = (DirectionalLayout) LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_recycle_item,null,false);
                }
                //获取列表项中的文本组件
                Text text = (Text) layout.findComponentById(ResourceTable.Id_item_text);
                //设置列表项数据
                text.setText("当前数据:"+getItem(i).toString());
                //返回该列表项的用户界面

                return layout;
            }
        });


    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}
相关推荐
JavaGuide3 分钟前
一条 SQL 语句在 MySQL 中是如何执行的?
java·数据库·后端·mysql
阿华的代码王国12 分钟前
【JavaEE】——多线程(join阻塞,计算,引用,状态)
java·开发语言·数据结构·java-ee
江喜原17 分钟前
微服务下设计一个注解标识是否需要登录
java·微服务·架构·登录
ABin-阿斌24 分钟前
SpringBoot 整合 Easy_Trans 实现翻译的具体介绍
java·spring boot·后端
菜鸟求带飞_26 分钟前
算法打卡:第十一章 图论part03
java·数据结构·算法·深度优先·图论
圆头圆脑圆JAVA26 分钟前
简单了解微服务--黑马(在更)
java·spring boot·微服务
木子欢儿34 分钟前
在 Debian 12 上安装 Java 21
java·运维·开发语言·debian
一二小选手37 分钟前
【高级编程】XML DOM4J解析XML文件(含案例)
xml·java
终末圆38 分钟前
MyBatis XML映射文件编写【后端 18】
xml·java·开发语言·后端·算法·spring·mybatis
就这个java爽!38 分钟前
超详细的XML介绍【附带dom4j操作XML】
xml·java·开发语言·数据库·青少年编程·eclipse