app性能日志工具

kotlin 复制代码
xxFragment.kt:

  PerformancePointUtil.getInstance().startUiLog(currentPageName)
  
  ....
  
 
  PerformancePointUtil.getInstance().endUiLog(currentPageName)
  
  
  
  
xxUtils.kt:

   private Logger mLogger;
   .....
    private String getUiMsg(boolean isStart, String pageName) {
        final String flag = isStart ? START : END;
        final StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(mProjectName)
                .append(UNDER_LINE)
                .append(UI)
                .append(UNDER_LINE)
                .append(pageName)
                .append(UNDER_LINE)
                .append(flag)
                .append(COLON)
                .append(System.currentTimeMillis());
        return stringBuilder.toString();
    }
	
	
    /***
     * when UI on create start output log
     * @param pageName UI page name,now is class name.
     */
    public void startUiLog(@NonNull String pageName) {
        logMsg(getUiMsg(true, pageName));
    }

    /***
     * when UI data set finished and draw completed output log.
     * @param pageName current UI page name,now is class simple name.
     */
    public void endUiLog(@NonNull String pageName) {
        logMsg(getUiMsg(false, pageName));
    }
	
	    public void logMsg(String msg) {
        if (mLogger == null){
            return;
        }

        if (mLogSwitch) {
            mLogger.log(LOG_LEVEL, msg);
        } else {
            mLogger.log(LOG_LEVEL, LOG_FAILED_MSG);
        }
    }
	

分析

1. endUiLog 目前具体应该写在哪个回调方法里?

在您的 xxFragment.kt 架构中,endUiLog 必须精准挂载在 LoadState.LoadSuccess 分支触发的 UI 渲染完成时。

然而,仅仅写在 updateUI(state.data) 后面是不够精准的。因为 RecyclerView.Adapter.notifyDataSetChanged() 或 setNewList() 只是把数据提交给了内存,此时 CPU 还在计算布局,GPU 还没有完成首帧的绘制。

💻 完美对齐"首帧渲染完成"的最佳写法

利用 View.post 机制,将 endUiLog 放入下一帧的队列中,确保日志输出时 RecyclerView 已经完成了在屏幕上的第一帧绘制:

kotlin 复制代码
private fun handleUiState(state: ExploreUiState) {
    when (state.loadState) {
        is LoadState.Loading -> {
            exploreAdapter?.setNewList(emptyList())
            showLoading()
            // 页面生命周期起点已经由外层触发,此处可执行通用动作
            onUiStart(javaClass.simpleName) 
        }

        is LoadState.LoadSuccess -> {
            setGridLayoutManager(state.bannerWidgetStyle)
            updateUI(state.data)
            
            // 🎯 核心:在视图队列最后执行,确保 RecyclerView 渲染绘制完毕
            binding?.exploreRvList?.post {
                PerformancePointUtil.getInstance().endUiLog(javaClass.simpleName)
            }
        }
        
        // ... 其他分支
    }
}

2. 如果接口请求失败(LoadError),是否也需要调用 endUiLog?

结论:不应该调用 endUiLog,而应该调用代表异常或中断的独立埋点函数。

❌ 为什么不能在 LoadError 中调用 endUiLog?

如果请求失败时也调用 endUiLog,后台系统通过 END时间戳 - START时间戳 计算出的耗时,就会把"接口报错卡顿的时间"误认为"页面成功加载的时间"。这会导致线上真实的页面渲染耗时数据被严重污染,无法筛选出真正因为 UI 卡顿导致的性能问题。

🛠️ 推荐的异常处理策略(3种方案)

根据车机系统(Volvo 级别)的严谨监控规范,面对 LoadError 应该采用以下策略:

方案 具体做法 适用场景
方案 A:单独定义取消/错误标签(最推荐) 在 PerformancePointUtil 中扩展一个 cancelUiLog 或 errorUiLog 方法,输出 _ERROR 或 _CANCEL 标记。 需要统计接口失败率和异常等待耗时。
方案 B:直接舍弃当前耗时 在 LoadError 中只处理异常 UI 展示(showExceptionLayout),不调用任何 end 埋点。 后台分析工具会自动过滤掉只有 START 没有 END 的死链数据。
方案 C:上报错误码(Error Code) 在日志拼装时追加错误码:项目_UI_页面_ERROR:时间戳:错误码。 便于自动化脚本一眼看出是因为网络超时的白屏,还是数据解析失败的白屏。

💻 方案 A 在 handleUiState 中的代码演进示例

kotlin 复制代码
is LoadState.LoadError -> {
    showExceptionLayout(state.loadState.exception)
    onUiReady()
    
    // ⚠️ 报错时不调 endUiLog,而是调专门的异常埋点
    PerformancePointUtil.getInstance().errorUiLog(javaClass.simpleName)
}

相关推荐
00后程序员张2 小时前
怎么用 Egret(白鹭引擎)打包 iOS 应用并上架 App Store?
android·ios·小程序·https·uni-app·iphone·webview
mmsx2 小时前
MapLibre 实战 09|Bug 单写着"地图被风刮走了":一个瓦片源工厂,是三个线上事故换来的
android·前端·开源
一技安身2 小时前
【信创】统信UOS 银河麒麟离线部署Python3.11完整方案
android·java·python3.11
墨狂之逸才3 小时前
Android WebView 初始缩放:什么时候该设置 100%,什么时候不要设置
android
淡淡的香烟3 小时前
AndroidKMP之导航和WebView
android
天空之城--15 小时前
Android逆向安全合规接单指南
android·安全
消失的旧时光-194317 小时前
Android 系统层扫盲 09:AMS、ATMS、WMS、PMS 到底分别管什么?
android·wms·pms·ams·aosp·atms
Godikov17 小时前
Android 系统级设备应用踩坑实录:sharedUserId 签名、SDK 授权失败 -4、开机自启与 U 盘 OTA 升级
android
IT毕设实战小研20 小时前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
企业数字化笔记21 小时前
固定资产历史数据怎么导入系统?Excel模板、字段映射和数据校验
android·java·数据库·后端