fix(ncm §31): 修两处 UI 数据竞态——返回首页行空白(staging发布) + 进第二个歌单显示上一歌单(换歌单清窗)

A. 返回首页各行 2~3s 空白:appstate_load_playlists 就地 memset(g_st.playlists[])
   与 home_src2 无锁逐行绑定竞态,刷新期间 playlist_count 保留旧值 → UI 读清零行。
   照搬 s_build[] staging 范式:网络落 s_pls[] → 成功后锁内原子发布(拷回+更新count),
   失败保留旧快照(断网离线浏览)。绝不就地清零 UI 可见数组。

B. 进第二个歌单显示上一歌单:playlist_open/refresh 同步路径不调 appstate_playlist_reset,
   pl_apply(1) 绑到上一歌单残留窗口(track_ids_count/songs)。
   新增窗口归属(歌单 id 唯一标识, 对搜索歌单同样成立): worker 首屏发布后
   appstate_playlist_window_set;refresh 目标≠归属(窗口is) → 同步 reset 再 pl_apply。
   同歌单手动刷新(id 同)保留旧内容(stale-while-revalidate)。

宿主回归:playlist_race_sim(新 F 并发读无清零态/G 开A→开B 不串)、window/search/
cache_evict/player_flow/stream_sim、test_ncm_core 宿主+mipsel 全 PASS;
build_ncm.sh -Wall -Wextra 0 warning;0 真实请求;未部署。
This commit is contained in:
AskaEth committed 2026-09-02 03:03:48 +08:00
1 parent 97b741cf56
commit 10690bc348
9 files changed
+290 -9

No files matched your search

+12
View File
@@ -272,6 +272,10 @@ static void *playlist_worker(void *arg)
}
g_plloaded_idx = tidx;
g_plloaded_gen = tgen;
/* §NEW bug B:首屏发布后标记窗口归属=目标歌单(失败/部分也归属,支持同歌单重试不清窗)。
* 过期(STALE)不标记——窗口仍属旧歌单。playlist_refresh 据此换歌单清窗。 */
if (rc != NCM_ERR_STALE)
appstate_playlist_window_set(tpl.id);
} else {
g_ens_err = rc; /* 补载失败 → snack + 占位行保留(滚动/点按再试) */
g_plloaded_idx = cur_active;
@@ -324,6 +328,14 @@ void playlist_refresh(void)
g_tgt.idx = g_st.active_playlist;
g_tgt.gen = appstate_playlist_begin(g_tgt.idx);
pthread_mutex_unlock(&g_plmu);
/* §NEW bug B(新进歌单显示上一个歌单内容):目标歌单与当前窗口归属不一致(跨歌单/搜索不同
* 结果)→ 同步清窗口,再 pl_apply。否则 pl_apply(1) 把新歌单标题绑到上一歌单残留窗口
* (track_ids_count/songs),新页瞬间渲染上一歌单行。同歌单手动刷新(id 相同)不清窗,
* 保留旧内容(stale-while-revalidate)——worker 异步重载替换。 */
if (!appstate_playlist_window_is(g_tgt.pl.id))
appstate_playlist_reset();
g_ens_first = 1; /* 首屏:重建索引 + 物化首段 */
g_pl_stale = 0;
g_plloading = 1;