一、什麼是ListContainer
ListContainer是用來呈現連續、多行資料的清單元件,包含一系列相同類型的清單項。如下圖所示:
二、ListContainer的架構視圖
ListContainer的架構視圖如下所示:
ListContainer作為清單,其中的清單項資料是由擴充卡Adapter提供的,擴充卡Adapter作為ListContainer和資料源之間的中介&橋梁,将資料源中的資料映射到要展示的ListContainer中,ListContainer負責以清單的形式顯示擴充卡Adapter提供的資料。
三、ListContainer的使用步驟
ListContainer的使用步驟主要包括:
1、建立ListContainer
2、建立清單項的布局
3、使用POJO類封裝資料源中與每個清單項對應的資料
4、構造資料源
5、構造擴充卡Adapter
6、将資料源關聯到擴充卡Adapter
7、将擴充卡Adapter應用到ListContainer
四、ListContainer的使用示例
示例的運作效果如下圖所示:
開發步驟如下:
1、建立ListContainer(ability_main.xml)
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:id="$+id:list_container"
ohos:height="match_parent"
ohos:width="match_parent"/>
2、建立清單項的布局(item.xml)
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_parent"
ohos:orientation="vertical">
ohos:id="$+id:name"
ohos:height="50vp"
ohos:width="match_parent"
ohos:padding="5vp"
ohos:auto_font_size="true"
ohos:text_alignment="center"/>
ohos:height="1vp"
ohos:width="match_parent"
ohos:background_element="#CCCCCC"/>
3、使用POJO類封裝資料源中與每個清單項對應的資料(Item.java)
POJO類指的是:隻包含屬性和相應的getter和setter,而沒有業務邏輯的類。
publicclass Item {
private String name;
publicItem(Stringname) {
this.name=name;
}
publicString getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name=name;
}
}
4、構造資料源(MainAbilitySlice.java)
publicclass MainAbilitySlice extends AbilitySlice {
@Override
publicvoid onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
List list = getData();
}
private List getData() {
List list = new ArrayList<>();
for(inti = 1; i <= 100; i++) {
list.add(new Item("Item "+ i));
}
returnlist;
}
}
5、構造擴充卡Adapter(MyItemProvider.java)
常用的擴充卡類是RecycleItemProvider,繼承該類時需要重寫四個方法:getCount()、getItem()、getItemId()和getComponent()。其中,對于方法getComponent(),當某個清單項從不可見變為可見時會自動調用該方法,在該方法中擴充卡Adapter會從資料源取資料,并将傳回的資料封裝在一個Component對象中,以便将該對象傳回給ListContainer,進而将資料映射到對應的清單項。
publicclass MyItemProvider extends RecycleItemProvider {
private List list;
private AbilitySlice slice;
publicMyItemProvider(List list, AbilitySlice slice) {
this.list = list;
this.slice = slice;
}
@Override
publicintgetCount() {
returnlist.size();
}
@Override
publicObject getItem(intposition) {
returnlist.get(position);
}
@Override
publiclong getItemId(intposition) {
returnposition;
}
@Override
publicComponent getComponent(intposition, Component convertComponent, ComponentContainer componentContainer) {
convertComponent = LayoutScatter.getInstance(slice)
.parse(ResourceTable.Layout_item, null,false);
Text text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
text.setText(list.get(position).getName());
returnconvertComponent;
}
}
6、将資料源關聯到擴充卡Adapter(MainAbilitySlice.java)
publicclass MainAbilitySlice extends AbilitySlice {
@Override
publicvoid onStart(Intent intent) {
......
List list = getData();
MyItemProvider myItemProvider = new MyItemProvider(list, this);
}
......
}
7、将擴充卡Adapter應用到ListContainer(MainAbilitySlice.java)
publicclass MainAbilitySlice extends AbilitySlice {
@Override
publicvoid onStart(Intent intent) {
......
MyItemProvider myItemProvider = new MyItemProvider(list, this);
ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_list_container);
listContainer.setItemProvider(myItemProvider);
}
......
}
五、擴充卡Adapter的優化
對于上面的第5步,當某個清單項從不可見變為可見時,對于自動調用的方法getComponent(),我們是根據清單項的布局檔案item.xml建立了一個清單項的執行個體。這樣的做法性能較差。因為系統會對變為不可見的清單項執行個體進行緩存,是以對于方法getComponent()中的第二個參數convertComponent有可能不為null。當convertComponent不為null時,說明系統把緩存中的某個清單項執行個體傳遞過來了,是以,完全可以複用該清單項執行個體,而沒有必要重新建立一個清單項執行個體。優化方式如下:
publicclass MyItemProvider extends RecycleItemProvider {
......
@Override
publicComponent getComponent(intposition, Component convertComponent, ComponentContainer componentContainer) {
if (convertComponent == null) {
convertComponent = LayoutScatter.getInstance(slice)
.parse(ResourceTable.Layout_item, null,false);
}
Text text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
text.setText(list.get(position).getName());
returnconvertComponent;
}
}
六、使用ViewHolder對擴充卡Adapter做終極優化
在上面的代碼中,得到清單項執行個體後(不管是新建立的清單項執行個體,還是從緩存中獲得的清單項執行個體),都要調用方法findComponentById()以獲得清單項中的子元件。調用方法findComponentById()是比較耗費性能的,是以好的做法是:在新建立清單項執行個體時,就調用方法findComponentById()以獲得清單項中的所有子元件,并且将所有子元件通過ViewHolder綁定到清單項執行個體。這樣,當從緩存中獲得清單項執行個體後,就無需再調用方法findComponentById()了,直接獲得清單項執行個體綁定的ViewHolder就可以得到所有子元件了。優化方式如下:
publicclass MyItemProvider extends RecycleItemProvider {
......
@Override
publicComponent getComponent(intposition, Component convertComponent, ComponentContainer componentContainer) {
ViewHolder viewHolder;
if (convertComponent == null) {
convertComponent = LayoutScatter.getInstance(slice)
.parse(ResourceTable.Layout_item, null,false);
viewHolder = new ViewHolder();
viewHolder.text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
convertComponent.setTag(viewHolder);
} else{
viewHolder = (ViewHolder) convertComponent.getTag();
}
viewHolder.text.setText(list.get(position).getName());
returnconvertComponent;
}
class ViewHolder {
Text text;
}
}
如果你了解了為什麼要這麼優化,相信你會發現:當清單項中隻有一個子元件時,也可以不引入ViewHolder,而是将這個子元件直接綁定到清單項執行個體。代碼如下所示:
publicclass MyItemProvider extends RecycleItemProvider {
......
@Override
publicComponent getComponent(intposition, Component convertComponent, ComponentContainer componentContainer) {
Text text;
if (convertComponent == null) {
convertComponent = LayoutScatter.getInstance(slice)
.parse(ResourceTable.Layout_item, null,false);
text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
convertComponent.setTag(text);
} else{
text = (Text) convertComponent.getTag();
}
text.setText(list.get(position).getName());
returnconvertComponent;
}
}
示例源代碼,請見附件。
歡迎訂閱我的專欄【圖解鴻蒙】:
https://harmonyos.51cto.com/column/27
©著作權歸作者和HarmonyOS技術社群共同所有,如需轉載,請注明出處,否則将追究法律責任
【編輯推薦】
【責任編輯:jianghua TEL:(010)68476606】
點贊 0