fix: improve ToolHub startup and cleanup stability

This commit is contained in:
7015725
2026-05-12 10:00:32 +08:00
parent 523d6e2044
commit 0037aefcb7
4 changed files with 86 additions and 124 deletions

View File

@@ -2311,78 +2311,7 @@ var scInlineState = {
lastQuery: ""
};
// # 图标缓存与队列(避免每次重渲染都重复取 icon减少卡顿
// 这段代码的主要内容/用途:为内联列表提供轻量级 icon 缓存与串行加载队列,避免一次性开太多线程。
var scIconCache = {};
var scIconQueue = [];
var scIconWorkerRunning = false;
function __scIconKey(it) {
try { return __scStr(it.pkg) + '|' + __scStr(it.shortcutId) + '|' + __scStr(it.userId); } catch(e) { return ''; }
}
function __scLoadIconForItem(it) {
// 这段代码的主要内容/用途:优先取快捷方式图标,失败则回退到应用图标。
try {
if (!it) return null;
if (it.shortcutInfo) {
try {
var la = context.getSystemService(android.content.Context.LAUNCHER_APPS_SERVICE);
if (la) {
var dr = la.getShortcutIconDrawable(it.shortcutInfo, 0);
if (dr) return dr;
}
} catch(eS0) { safeLog(null, 'e', "catch " + String(eS0)); }
}
try {
var pm = context.getPackageManager();
return pm.getApplicationIcon(__scStr(it.pkg));
} catch(eA0) { safeLog(null, 'e', "catch " + String(eA0)); }
} catch(eAll0) { safeLog(null, 'e', "catch " + String(eAll0)); }
return null;
}
function __scEnqueueIconLoad(it, iv) {
try {
var key = __scIconKey(it);
if (!key) return;
if (scIconCache[key]) {
try { iv.setImageDrawable(scIconCache[key]); } catch(eSet0) { safeLog(null, 'e', "catch " + String(eSet0)); }
return;
}
// # 记录 tag防止滚动/重绘后错位
try { iv.setTag(key); } catch(eTag0) { safeLog(null, 'e', "catch " + String(eTag0)); }
scIconQueue.push({ key: key, it: it, iv: iv });
if (!scIconWorkerRunning) {
scIconWorkerRunning = true;
new java.lang.Thread(new java.lang.Runnable({
run: function() {
while (true) {
var job = null;
try { if (scIconQueue.length > 0) job = scIconQueue.shift(); } catch(eQ0) { job = null; }
if (!job) break;
var dr = null;
try { dr = __scLoadIconForItem(job.it); } catch(eLd0) { dr = null; }
if (dr) scIconCache[job.key] = dr;
try {
self.runOnUiThreadSafe(function() {
try {
if (!job || !job.iv) return;
var cur = null;
try { cur = job.iv.getTag(); } catch(eTg0) { cur = null; }
if (cur && String(cur) === String(job.key) && dr) {
job.iv.setImageDrawable(dr);
}
} catch(eUi0) { safeLog(null, 'e', "catch " + String(eUi0)); }
});
} catch(ePost0) { safeLog(null, 'e', "catch " + String(ePost0)); }
}
scIconWorkerRunning = false;
}
})).start();
}
} catch(eEnq0) { safeLog(null, 'e', "catch " + String(eEnq0)); }
}
// # 图标缓存与加载已统一使用下方 __scIconLoader / __scRequestIcon避免维护两套后台线程队列。
// # 折叠头部(点击展开/收起)
var scHeader = new android.widget.LinearLayout(context);
scHeader.setOrientation(android.widget.LinearLayout.HORIZONTAL);
@@ -2410,10 +2339,10 @@ scRefreshTv.setOnClickListener(new android.view.View.OnClickListener({
try {
scInlineState.forceReload = true;
scInlineState.loaded = false;
// 清空 icon 缓存,避免旧图标占用内存且影响新列表显示
try { scIconCache = {}; } catch(eC0) { safeLog(null, 'e', "catch " + String(eC0)); }
try { scIconQueue = []; } catch(eC1) { safeLog(null, 'e', "catch " + String(eC1)); }
try { scIconWorkerRunning = false; } catch(eC2) { safeLog(null, 'e', "catch " + String(eC2)); }
// 清空当前内联列表的图标缓存,避免旧图标占用内存且影响新列表显示
try { __scIconCache = {}; } catch(eC0) { safeLog(null, 'e', "catch " + String(eC0)); }
try { __scIconKeys = []; } catch(eC1) { safeLog(null, 'e', "catch " + String(eC1)); }
try { __scIconInFlight = {}; } catch(eC2) { safeLog(null, 'e', "catch " + String(eC2)); }
// 若当前已展开,立即触发重新加载与渲染
if (scInlineState.expanded) __scEnsureLoadedAndRender();
} catch(eR) { safeLog(null, 'e', "catch " + String(eR)); }

View File

@@ -119,12 +119,12 @@ FloatBallAppWM.prototype.close = function() {
}
} catch (eIcon) {}
try {
if (self.__scIconLoaderSingleton && self.__scIconLoaderSingleton.ht) {
if (android.os.Build.VERSION.SDK_INT >= 18) self.__scIconLoaderSingleton.ht.quitSafely();
else self.__scIconLoaderSingleton.ht.quit();
if (this.__scIconLoaderSingleton && this.__scIconLoaderSingleton.ht) {
if (android.os.Build.VERSION.SDK_INT >= 18) this.__scIconLoaderSingleton.ht.quitSafely();
else this.__scIconLoaderSingleton.ht.quit();
}
} catch (eScIcon) {}
try { self.__scIconLoaderSingleton = null; } catch (eScIcon2) {}
try { this.__scIconLoaderSingleton = null; } catch (eScIcon2) {}
safeLog(this.L, 'i', "close done");
@@ -158,8 +158,8 @@ FloatBallAppWM.prototype.dispose = function() {
// # 清理单例引用
try {
if (self.__shortcutPickerSingleton === this.__shortcutPickerSingleton) {
self.__shortcutPickerSingleton = null;
if (this.__shortcutPickerSingleton) {
this.__shortcutPickerSingleton = null;
}
} catch (e) {}
@@ -245,50 +245,83 @@ FloatBallAppWM.prototype.startAsync = function(entryProcInfo, closeRule) {
);
if (cfgRcv) this.state.receivers.push(cfgRcv);
h.post(new JavaAdapter(java.lang.Runnable, {
run: function() {
try {
self.state.wm = context.getSystemService(android.content.Context.WINDOW_SERVICE);
self.state.density = context.getResources().getDisplayMetrics().density;
if (self.L) self.L.updateConfig(self.config);
self.state.screen = self.getScreenSizePx();
self.state.lastRotation = self.getRotation();
self.state.loadedPos = self.loadSavedPos();
self.createBallViews();
self.state.ballLp = self.createBallLayoutParams();
var startBox = { ok: false, err: "启动确认超时", added: false };
var startLatch = new java.util.concurrent.CountDownLatch(1);
var posted = false;
try {
posted = h.post(new JavaAdapter(java.lang.Runnable, {
run: function() {
try {
self.state.wm.addView(self.state.ballRoot, self.state.ballLp);
self.state.addedBall = true;
} catch (eAdd) {
try { self.toast("悬浮球 addView 失败: " + String(eAdd)); } catch (eT) {}
if (self.L) self.L.fatal("addView ball fail err=" + String(eAdd));
self.state.addedBall = false;
try { self.close(); } catch (eC) {}
return;
}
self.state.wm = context.getSystemService(android.content.Context.WINDOW_SERVICE);
self.state.density = context.getResources().getDisplayMetrics().density;
self.setupDisplayMonitor();
self.touchActivity();
if (self.L) self.L.updateConfig(self.config);
if (self.L) {
self.L.i("start ok actionClose=" + String(self.config.ACTION_CLOSE_ALL));
self.L.i("ball x=" + String(self.state.ballLp.x) + " y=" + String(self.state.ballLp.y) + " sizeDp=" + String(self.config.BALL_SIZE_DP));
self.state.screen = self.getScreenSizePx();
self.state.lastRotation = self.getRotation();
self.state.loadedPos = self.loadSavedPos();
self.createBallViews();
self.state.ballLp = self.createBallLayoutParams();
try {
self.state.wm.addView(self.state.ballRoot, self.state.ballLp);
self.state.addedBall = true;
startBox.added = true;
} catch (eAdd) {
startBox.ok = false;
startBox.err = "悬浮球 addView 失败: " + String(eAdd);
try { self.toast(startBox.err); } catch (eT) {}
if (self.L) self.L.fatal("addView ball fail err=" + String(eAdd));
self.state.addedBall = false;
try { self.close(); } catch (eC) {}
return;
}
self.setupDisplayMonitor();
self.touchActivity();
startBox.ok = true;
startBox.err = "";
if (self.L) {
self.L.i("start ok actionClose=" + String(self.config.ACTION_CLOSE_ALL));
self.L.i("ball x=" + String(self.state.ballLp.x) + " y=" + String(self.state.ballLp.y) + " sizeDp=" + String(self.config.BALL_SIZE_DP));
}
} catch (eAll) {
startBox.ok = false;
startBox.err = "启动异常: " + String(eAll);
try { self.toast(startBox.err); } catch (eTT2) {}
if (self.L) self.L.fatal("start runnable err=" + String(eAll));
try { self.close(); } catch (eC2) {}
} finally {
try { startLatch.countDown(); } catch (eLatch) {}
}
} catch (eAll) {
try { self.toast("启动异常: " + String(eAll)); } catch (eTT2) {}
if (self.L) self.L.fatal("start runnable err=" + String(eAll));
try { self.close(); } catch (eC2) {}
}
}));
} catch (ePost) {
posted = false;
startBox.ok = false;
startBox.err = "启动任务投递失败: " + String(ePost);
try { startLatch.countDown(); } catch (eLatch2) {}
}
if (!posted) {
startBox.ok = false;
if (!startBox.err) startBox.err = "启动任务投递失败";
} else {
try {
var done = startLatch.await(2500, java.util.concurrent.TimeUnit.MILLISECONDS);
if (!done && self.L) self.L.e("start confirm timeout; addView result unknown");
} catch (eWait) {
startBox.ok = false;
startBox.err = "启动确认等待异常: " + String(eWait);
}
}));
}
return {
ok: true,
msg: "已按 WM 专属 HandlerThread 模型启动Shell 默认 Action失败广播桥兜底Content URI 已启用)",
ok: !!startBox.ok,
err: String(startBox.err || ""),
msg: startBox.ok ? "悬浮球 addView 已确认成功" : String(startBox.err || "启动失败"),
preCloseBroadcastSent: preCloseSent,
closeAction: String(this.config.ACTION_CLOSE_ALL),
receiverRegisteredOnMain: {

View File

@@ -54,19 +54,19 @@
"size": 20386
},
"th_14_panels.js": {
"sha256": "65528739877540cdd457017ebd083e1ad0f1f911706129d75a88647c48a59c51",
"size": 220509
"sha256": "a237b164e29f4a581893b86bd7d3f9776dc0ecc7a56ecc53f9465525fa117253",
"size": 217295
},
"th_15_extra.js": {
"sha256": "c8e10fe54a965fe7b27f0996b2f2636655077e39df774d6cbb1e73c5b36553fc",
"size": 62625
},
"th_16_entry.js": {
"sha256": "8c7d2d8dfa1dc51b47a01be8639a9da78cb40670c66cc8f78d339afecfd83be5",
"size": 11125
"sha256": "6bb08673d720665e2d6a04d4b2021cc7f836818f4781daff59cb7b382322d1c9",
"size": 12285
}
},
"keyId": "toolhub-targets-2026-rsa3072",
"schema": 2,
"version": 20260507155220
"version": 20260512020008
}

View File

@@ -1 +1 @@
TwIGuNRj9b0pIqiICJpA3vNxwNtQfsSj4LQKyOcUfuVxbbDsAJ1SZWra9ioDdd1jdjo8jEiSHMZ5JgDdKSkrUQZwUpQYsBXdtFFS2Zb5aoGk7QLgrgHRoJvvJOinU3/DLS93by3msNMoEJmZLQEoa4ltXK7hehc5dclp82ZOXg3p5A1OCgdzavGzSqPfg4eH1o3GHzS2I/zDhZgzrbKNcoKUsy//fr5E34ePQ4aWNXAmcyQFNXLT8aCDL+yXn3wjbTgASuHS+GncwbYJ5y4/toMyW+EJNX0xiOsIa7OFA7jRfX0U6qqgZH0fW/jGlZNeJhnqZYfOpjKIPy7t7B5iThJT0iiJ6L4X/mjUe9ggO/YAhJ7g4Vp8m/g5LpmWpVPLRwYJje6Q5Ypulm95CaBek2FEjXwqGa1hsCQ1MfMj1rCwfn7biLH1Vkfff+JgoRvE/2JWbPMLU+j1jCNOLWVUPIpTsazu8/kR4NkjJPUm7uZX5ogtfRhGbkLl08+lB8Lm
axGRqLze6TvsjEgpjNjRGL0u2CHxBCSwWZ8AKQBZ2Q9Gr8rMajyTkNt6vRW0aHPWaJhM9Silyh/3VIoy4iz0Id2RltAwADV7XygLGL2jMGlHsjC2U1g8bavgL1JKK/UY0WvnQ1fUgI2bDqWA2eN/SQvP0/DbRwOeheCvcNrf5aHxMuEYyorIbbhFxsqGXb8Uut6ieKe2aUV5jSL1LOatt2QKgnOM5ylpRmf3M9w3g8f4SDjHKhCup6K7H52ooazoFmMP030suXVhn1vmujrZtQtcgmzMU6hI1ZSZOcPIekgWxzIlJ2ktXxR/b9TlQ4JcEtxG2D/jIx02M0mQXE9kfZZJ7I3g6h2FNc4YdJS51pXr7YvtGPevR6yxP+/J5e6fVcm+W5EW8eFHzrtyhBI8zvG7vJSCYBV+jwl/XNznwnx0whduQ7RqZMM4++xdzyew5wtIWnlVxI4wqX+B852cnSU/EdTPu2HoBt+TfqEO5p7oDok1pO01i5BWghkvujKt