fix(gui): use correct threads for code from close and reload actions (#2684)

This commit is contained in:
Skylot
2025-11-21 20:15:23 +00:00
parent 2fba204b33
commit cc1beab0b5
2 changed files with 55 additions and 50 deletions
@@ -21,13 +21,13 @@ import jadx.api.metadata.ICodeNodeRef;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException;
import jadx.gui.jobs.LoadTask;
import jadx.gui.treemodel.JClass;
import jadx.gui.treemodel.JNode;
import jadx.gui.treemodel.JPackage;
import jadx.gui.treemodel.JRoot;
import jadx.gui.ui.MainWindow;
import jadx.gui.utils.JNodeCache;
import jadx.gui.utils.NLS;
import jadx.gui.utils.UiUtils;
public class TreeExpansionService {
@@ -62,9 +62,9 @@ public class TreeExpansionService {
}
public void load(List<String> treeExpansions) {
List<TreePath> expandedPaths = new ArrayList<>();
mainWindow.getBackgroundExecutor().execute(NLS.str("progress.load"),
mainWindow.getBackgroundExecutor().execute(new LoadTask<>(
() -> {
List<TreePath> expandedPaths = new ArrayList<>();
loadPaths(treeExpansions, expandedPaths);
// send expand event to load sub-nodes and wait for completion
UiUtils.uiRunAndWait(() -> expandedPaths.forEach(path -> {
@@ -74,11 +74,12 @@ public class TreeExpansionService {
throw new JadxRuntimeException("Tree expand error", e);
}
}));
return expandedPaths;
},
s -> {
expandedPaths -> {
// expand paths after a loading task is finished
expandedPaths.forEach(tree::expandPath);
});
}));
}
private void loadPaths(List<String> treeExpansions, List<TreePath> expandedPaths) {
@@ -32,7 +32,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import javax.swing.AbstractAction;
@@ -377,8 +376,10 @@ public class MainWindow extends JFrame {
if (!ensureProjectIsSaved()) {
return;
}
closeAll();
updateProject(new JadxProject(this));
UiUtils.bgRun(() -> {
closeAll();
updateProject(new JadxProject(this));
});
}
private void saveProject() {
@@ -540,6 +541,7 @@ public class MainWindow extends JFrame {
synchronized (ReloadProject.EVENT) {
saveAll();
closeAll();
System.gc();
loadFiles(() -> {
menuBar.reloadShortcuts();
events().send(ReloadSettingsWindow.INSTANCE);
@@ -571,25 +573,16 @@ public class MainWindow extends JFrame {
onFinish.run();
return;
}
AtomicReference<Exception> wrapperException = new AtomicReference<>();
backgroundExecutor.execute(NLS.str("progress.load"),
() -> {
try {
wrapper.open();
} catch (Exception e) {
wrapperException.set(e);
LOG.error("Project load error", e);
closeAll();
}
},
status -> {
if (wrapperException.get() != null) {
closeAll();
Exception e = wrapperException.get();
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else {
throw new JadxRuntimeException("Project load error", e);
}
}
if (status == TaskStatus.CANCEL_BY_MEMORY) {
showHeapUsageBar();
UiUtils.errorMessage(this, NLS.str("message.memoryLow"));
@@ -600,8 +593,7 @@ public class MainWindow extends JFrame {
return;
}
checkLoadedStatus();
onOpen();
onFinish.run();
onOpen(onFinish);
});
}
@@ -612,19 +604,21 @@ public class MainWindow extends JFrame {
}
private void closeAll() {
notifyLoadListeners(false);
UiUtils.notUiThreadGuard();
cancelBackgroundJobs();
navController.reset();
tabbedPane.reset();
clearTree();
resetCache();
LogCollector.getInstance().reset();
UiUtils.uiRunAndWait(() -> {
tabsController.forceCloseAllTabs();
tabbedPane.reset();
navController.reset();
shortcutsController.reset();
clearTree();
UiUtils.resetClipboardOwner();
update();
});
wrapper.close();
tabsController.forceCloseAllTabs();
shortcutsController.reset();
UiUtils.resetClipboardOwner();
System.gc();
UiUtils.uiRun(this::update);
LogCollector.getInstance().reset();
resetCache();
notifyLoadListeners(false);
}
private void checkLoadedStatus() {
@@ -647,21 +641,23 @@ public class MainWindow extends JFrame {
}
}
private void onOpen() {
private void onOpen(Runnable onFinish) {
initTree();
updateLiveReload(project.isEnableLiveReload());
BreakpointManager.init(project.getFilePaths().get(0).toAbsolutePath().getParent());
treeExpansionService.load(project.getTreeExpansions());
List<EditorViewState> openTabs = project.getOpenTabs(this);
backgroundExecutor.execute(NLS.str("progress.load"),
backgroundExecutor.startLoading(
() -> preLoadOpenTabs(openTabs),
status -> {
() -> {
restoreOpenTabs(openTabs);
runInitialBackgroundJobs();
notifyLoadListeners(true);
update();
notifyLoadListeners(true);
onFinish.run();
checkIfCodeHasNonPrintableChars();
runInitialBackgroundJobs();
});
// queue tree state restore after loading task
treeExpansionService.load(project.getTreeExpansions());
}
public void passesReloaded() {
@@ -1592,18 +1588,26 @@ public class MainWindow extends JFrame {
if (!ensureProjectIsSaved()) {
return;
}
settings.setTreeWidth(treeSplitPane.getDividerLocation());
settings.saveWindowPos(this);
settings.setMainWindowExtendedState(getExtendedState());
if (debuggerPanel != null) {
saveSplittersInfo();
}
heapUsageBar.reset();
closeAll();
editorThemeManager.unload();
dispose();
System.exit(0);
UiUtils.bgRun(() -> {
try {
settings.setTreeWidth(treeSplitPane.getDividerLocation());
settings.saveWindowPos(this);
settings.setMainWindowExtendedState(getExtendedState());
if (debuggerPanel != null) {
saveSplittersInfo();
}
closeAll();
UiUtils.uiRunAndWait(() -> {
heapUsageBar.reset();
editorThemeManager.unload();
dispose();
});
} catch (Exception e) {
LOG.error("Close window error", e);
} finally {
System.exit(0);
}
});
}
private void saveOpenTabs() {