* Copyright (c) Huawei Device Co., Ltd. 2024-2025. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { settings } from '@kit.BasicServicesKit';
import { LogDomain, Logger } from '@ohos/basicutils';
import { SCBConstants, SettingsConstants, SettingsKeyConstants } from '@ohos/commonconstants';
import {
DeviceHelper,
GlobalContext,
IconExtendParam,
IconResourceManager,
TaskInfo,
SettingsUtil
} from '@ohos/frameworkwrapper';
import { DataAndRefreshUtils } from '@ohos/frameworkwrapper/src/main/ets/resourcemanager/fwk/DataAndRefreshUtils';
import IconInfo from '@ohos/frameworkwrapper/src/main/ets/resourcemanager/IconInfo';
import { IconTaskManager } from '@ohos/frameworkwrapper/src/main/ets/resourcemanager/IconTaskManager';
import { IconChangeListener } from '../AppModel';
import { LayoutRefreshManager, RefreshViewDataCollection } from './LayoutRefreshManager';
import { RefreshStrategy } from './RefreshStrategy';
const TAG = 'MiniBatchRefreshStrategy';
const log: Logger = Logger.getLogHelper(LogDomain.HOME);
const REFRESH_BATCH_COUNT: number = 10;
* 默认处理策略,用于针对布局上图标控件很多时的场景,因为控件很多常驻内存较高,避免出现内存峰值过高场景,需要边获取资源边转化刷新控件并释放bms内存
*/
export class MiniBatchRefreshStrategy extends RefreshStrategy {
public async refreshDataAndView(iconChangeListener: IconChangeListener[],
deliverAppIconInfosMap: Map<string, IconInfo>, allFinished: () => void): Promise<void> {
if (DeviceHelper.is2In1DevicePcType() || DeviceHelper.isPC()) {
await this.refreshDataAndViewByListener(iconChangeListener, deliverAppIconInfosMap);
} else {
await this.refreshDataAndViewByCache(iconChangeListener, deliverAppIconInfosMap);
}
allFinished();
}
private async refreshDataAndViewByCache(iconChangeListener: IconChangeListener[],
deliverAppIconInfosMap: Map<string, IconInfo>): Promise<void> {
iconChangeListener.forEach((listener: IconChangeListener) => {
if (!listener.bundleName) {
listener.onIconResourceChange();
}
});
let collection: RefreshViewDataCollection = LayoutRefreshManager.getInstance().sortLayout(deliverAppIconInfosMap);
collection.fillingExtraView(iconChangeListener);
let tasks: TaskInfo[][] = [];
let taskInfos: TaskInfo[] = collection.currentViews;
await this.getDataAndRefresh(tasks, taskInfos, iconChangeListener);
taskInfos = collection.otherViews;
taskInfos.push(...collection.backgroundViews);
taskInfos.push(...collection.extraViews);
await this.getDataAndRefresh(tasks, taskInfos, iconChangeListener);
}
private async refreshDataAndViewByListener(iconChangeListener: IconChangeListener[],
deliverAppIconInfosMap: Map<string, IconInfo>): Promise<void> {
let taskInfos: TaskInfo[] = [];
this.refreshReady(iconChangeListener, deliverAppIconInfosMap, taskInfos);
let tasks: TaskInfo[][] = [];
tasks = IconTaskManager.spliceTask(taskInfos);
await Promise.all(tasks.map(async task => {
log.showInfo(TAG, `childTask length = ${task.length} tasks length = ${tasks.length}`);
await this.runTask(task, iconChangeListener);
}));
}
private refreshReady(iconChangeListener: IconChangeListener[], deliverAppIconInfosMap: Map<string, IconInfo>,
taskInfos: TaskInfo[]): void {
iconChangeListener.forEach((listener: IconChangeListener) => {
if (!listener.bundleName) {
listener.onIconResourceChange();
return;
}
let param = new IconExtendParam();
param.bundleName = deliverAppIconInfosMap.has(listener.bundleName) ?
listener.bundleName + SCBConstants.BUNDLENAME_APPEND_TEMPLATE : listener.bundleName;
let taskInfo: TaskInfo = new TaskInfo(listener.bundleName, listener.moduleName ?? '',
listener.abilityName ?? '', param);
taskInfos.push(taskInfo);
});
}
private async getDataAndRefresh(tasks: TaskInfo[][], taskInfos: TaskInfo[],
iconChangeListener: IconChangeListener[]): Promise<void> {
tasks = IconTaskManager.spliceTask(taskInfos);
await Promise.all(tasks.map(async (task) => {
log.showInfo(TAG, `childTask length = ${task.length} tasks length = ${tasks.length}`);
await this.runTask(task, iconChangeListener);
}));
}
private async runTask(task: TaskInfo[], iconChangeListener: IconChangeListener[]): Promise<void> {
while (task.length > 0) {
let childTask: TaskInfo[] = task.splice(0, REFRESH_BATCH_COUNT);
await IconResourceManager.getInstance().refreshIconResourceBatch(childTask);
LayoutRefreshManager.getInstance().refreshViewBatch(iconChangeListener, childTask);
}
}
public cancelStrategy(): void {
log.showWarn(TAG, 'cancel Strategy, batchId: %{public}d', this.getBatchId());
super.cancelStrategy();
GlobalContext.getContext().eventHub.emit(DataAndRefreshUtils.EVENT_STRATEGY_CANCEL_FINISH);
}
}