From 9f85e4a63b57b2ea1f4cf690655ce41a73bba5ca Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Sun, 24 Feb 2019 12:25:19 +0800 Subject: [PATCH] Do not run GameVersion.minecraftVersion on UI thread --- .../jackhuang/hmcl/ui/versions/GameItem.java | 29 ++++++++++++++----- .../java/org/jackhuang/hmcl/util/Lang.java | 11 +++++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java index 6ac923ec2..eaa81fa88 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameItem.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.ui.versions; +import javafx.application.Platform; import javafx.beans.property.*; import javafx.scene.control.Control; import javafx.scene.control.Skin; @@ -25,11 +26,20 @@ import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.game.GameVersion; import org.jackhuang.hmcl.setting.Profile; +import static org.jackhuang.hmcl.util.Lang.handleUncaught; +import static org.jackhuang.hmcl.util.Lang.threadPool; import static org.jackhuang.hmcl.util.StringUtils.removePrefix; import static org.jackhuang.hmcl.util.StringUtils.removeSuffix; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + public class GameItem extends Control { + + private static final ThreadPoolExecutor POOL_VERSION_RESOLVE = threadPool("VersionResolve", true, 1, 1, TimeUnit.SECONDS); + private final Profile profile; private final String version; private final StringProperty title = new SimpleStringProperty(); @@ -40,16 +50,19 @@ public class GameItem extends Control { this.profile = profile; this.version = id; - String game = GameVersion.minecraftVersion(profile.getRepository().getVersionJar(id)).orElse("Unknown"); - - StringBuilder libraries = new StringBuilder(game); - LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getVersion(id)); - analyzer.getForge().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", "")))); - analyzer.getLiteLoader().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", "")))); - analyzer.getOptiFine().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", "")))); + // GameVersion.minecraftVersion() is a time-costing job (up to ~200 ms) + CompletableFuture.supplyAsync(() -> GameVersion.minecraftVersion(profile.getRepository().getVersionJar(id)).orElse("Unknown"), POOL_VERSION_RESOLVE) + .thenAcceptAsync(game -> { + StringBuilder libraries = new StringBuilder(game); + LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(profile.getRepository().getVersion(id)); + analyzer.getForge().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.forge")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)forge", "")))); + analyzer.getLiteLoader().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.liteloader")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)liteloader", "")))); + analyzer.getOptiFine().ifPresent(library -> libraries.append(", ").append(i18n("install.installer.optifine")).append(": ").append(modifyVersion(game, library.getVersion().replaceAll("(?i)optifine", "")))); + subtitle.set(libraries.toString()); + }, Platform::runLater) + .exceptionally(handleUncaught); title.set(id); - subtitle.set(libraries.toString()); image.set(profile.getRepository().getVersionIconImage(version)); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java index ad6b50243..6dc07855d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java @@ -25,6 +25,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.function.Function; /** * @@ -199,6 +200,16 @@ public final class Lang { return t; } + /** + * This is a useful function to prevent exceptions being eaten when using CompletableFuture. + * You can write: + * ... .exceptionally(handleUncaught); + */ + public static final Function handleUncaught = e -> { + handleUncaughtException(e); + return null; + }; + public static void handleUncaughtException(Throwable e) { Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e); }