堆栈中有takeScreenShot字段,说明应用有对截屏事件做特殊处理。
EVENTNAME = APP_INPUT_BLOCK TIMESTAMP = 2025/05/10-13:32:09:970 PID = 16610 UID = 20020195 TID = 16610 PACKAGE_NAME = com.hx.example PROCESS_NAME = com.hx.example eventLog_action = ffrt,t:input,t,cmd:c,cmd:dam,tr,k:SysRqFile,cmd:m eventLog_interval = 10 MSG = Fault time:2025/05/10-13:32:05 User input does not respond! Timestamp:2025-05-10 13:32:06:52 Tid:16610, Name:com.hx.example #00 pc 0000000000f348bc /system/lib64/libskia_canvaskit.z.so(neon::matrix_scale_translate(unsigned long, void**, unsigned long, unsigned long, float vector[4], float vector[4], float vector[4], float vector[4], float vector[4], float vector[4], float vector[4], float vector[4])+24)(41c7e50437de39b1aaa05208f048d2dd) #01 pc 0000000000f77a64 /system/lib64/libskia_canvaskit.z.so(neon::start_pipeline(unsigned long, unsigned long, unsigned long, unsigned long, void**)+4496)(41c7e50437de39b1aaa05208f048d2dd) #02 pc 00000000011281f4 /system/lib64/libskia_canvaskit.z.so(SkRasterPipelineBlitter::blitRect(int, int, int, int)+712)(41c7e50437de39b1aaa05208f048d2dd) #03 pc 0000000000f2e33c /system/lib64/libskia_canvaskit.z.so(SkScan::FillRect(SkRect const&, SkRasterClip const&, SkBlitter*)+140)(41c7e50437de39b1aaa05208f048d2dd) #04 pc 0000000000f2d998 /system/lib64/libskia_canvaskit.z.so(SkDraw::drawRect(SkRect const&, SkPaint const&, SkMatrix const*, SkRect const*) const+1160)(41c7e50437de39b1aaa05208f048d2dd) #05 pc 0000000000f2cec0 /system/lib64/libskia_canvaskit.z.so(SkDraw::drawBitmap(SkBitmap const&, SkMatrix const&, SkRect const*, SkSamplingOptions const&, SkPaint const&) const+964)(41c7e50437de39b1aaa05208f048d2dd) // ... #21 at takeScreenShot (entry|@lk/lk_oh_fitness_others|1.0.1|src/main/ets/pageshowaspect/help/ScreenShotHelper.ts:19:1)
05-10 13:31:46.629 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:46.630 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:46.631 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:49.286 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:49.287 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:50.011 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:50.012 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:54.765 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:54.767 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:55.507 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined 05-10 13:31:55.509 16610 16610 I A03D00/com.hx.example/JSAPP: screenshot happenedundefined
优化耗时,当主线程中遇到一些难以避免的耗时操作时,例如同步网络请求、大文件读写、复杂计算、音频处理、数据传输等,可以从以下角度进行性能优化:
控制执行次数,当遇到用户高频事件输入时,根据业务场景,可以选择节流、防抖或限制次数的方式进行优化:
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 防抖:在一段时间内函数被多次触发,防抖让函数在一段时间后最终只执行一次
* 返回的函数不需要传参,直接使用this访问外部数据即可
* @param fn 传入频繁触发的函数
* @param delay 延迟时间
* @returns
*/
export function debounce(fn: Function, delay: number = 1000) {
let timer: number;
return () => {
clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay);
};
}
/**
* 节流:在规定的时间内,只执行一次
* @param callBack
* @param delay
* @param immediately 是否立即执行
* @returns
*/
export function throttle(callBack: Function, delay: number = 1000, immediately: boolean = true) {
let timer = 0;
if (immediately) {
return () => {
if (Date.now() - timer >= delay) {
callBack();
timer = Date.now();
}
};
} else {
return () => {
if (timer) {
return;
}
timer = setTimeout(() => {
callBack();
timer = 0;
}, delay);
};
}
}
@Entry
@Component
export struct ScreenShotPage {
@State remind: string = '未截图';
private uiContext = this.getUIContext();
private promptAction = this.uiContext.getPromptAction();
private customDialogComponentId: number = 0;
private isShowing = false;
dfn = debounce(() => {
this.simulateBlockingOperation();
});
tfn = throttle(() => {
this.simulateBlockingOperation();
});
@State count: number = 0;
@State consoleText: string = '';
@Builder
screenShotDialog() {
Column({ space: 15 }) {
Text('应用内截图事件弹窗')
.fontSize(20)
Button('关闭').onClick(() => {
try {
this.promptAction.closeCustomDialog(this.customDialogComponentId);
} catch (error) {
console.error(`closeCustomDialog error code is ${error.code}, message is ${error.message}`);
}
})
}.padding(15)
}
aboutToAppear(): void {
window.getLastWindow(this.getUIContext().getHostContext(), (err: BusinessError, data: window.Window) => {
if (err) {
console.error(`GetLastWindow failed, error code: ${err.code}, error message: ${err.message}`);
}
data.on('screenshot', () => {
if (data.isFocused()) {
this.remind = '应用内截图';
this.screenShotEventFunc();
} else {
this.remind = '非应用内截图';
}
});
});
}
screenShotEventFunc() {
if (this.isShowing) {
return;
}
this.promptAction.openCustomDialog({
builder: () => this.screenShotDialog(),
onDidDisappear: () => {
this.isShowing = false;
console.info('onDidDisappear: screenShotDialog');
}
}).then((dialogId: number) => {
this.customDialogComponentId = dialogId;
this.isShowing = true;
console.info('openCustomDialog success');
}).catch((error: BusinessError) => {
console.error(`openCustomDialog error code is ${error.code}, message is ${error.message}`);
});
}
// 模拟耗时操作的函数
simulateBlockingOperation(duration: number = 1000) {
this.count++;
this.consoleText += `\n${this.count}.开始执行`;
const startTime = new Date().getTime();
while (new Date().getTime() - startTime < duration) {
// 空循环模拟耗时计算
}
this.consoleText += '-结束执行';
}
build() {
Column({ space: 15 }) {
Column() {
Text('请多次截屏进行测试')
.fontSize(20)
Text(this.remind)
}
Button('长耗时任务1s').onClick(() => {
this.simulateBlockingOperation();
})
Button('节流方式执行耗时任务').onClick(() => {
this.tfn();
})
Button('防抖方式执行耗时任务').onClick(() => {
this.dfn();
})
Text(`执行次数:${this.count}`)
Text(this.consoleText)
}
.height('100%')
.width('100%')
.margin({ top: 30 })
}
}