From 4118096815808014139943ccce7d0759a75c43f9 Mon Sep 17 00:00:00 2001 From: Starryi Date: Tue, 24 Aug 2021 15:59:07 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-51919=20=E4=B8=BB=E9=A2=98=E5=88=87?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 新增模版主题功能: 主题管理面板和主题使用面板中对主题的获取操作,全部异步化, 提高加载性能 【改动思路】 同上 --- .../mainframe/theme/AsyncThemeFetcher.java | 86 +++++++++++++++++++ .../mainframe/theme/TemplateThemeBlock.java | 66 ++++---------- .../theme/TemplateThemeListPane.java | 63 +++++++++++--- .../theme/TemplateThemeManagePane.java | 40 +++++++-- 4 files changed, 185 insertions(+), 70 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/theme/AsyncThemeFetcher.java diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/AsyncThemeFetcher.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/AsyncThemeFetcher.java new file mode 100644 index 000000000..add47d6a0 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/AsyncThemeFetcher.java @@ -0,0 +1,86 @@ +package com.fr.design.mainframe.theme; + +import com.fr.base.theme.TemplateTheme; +import com.fr.base.theme.TemplateThemeConfig; +import com.fr.concurrent.NamedThreadFactory; +import com.fr.module.ModuleContext; + +import java.util.concurrent.ExecutorService; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/8/24 + */ +public class AsyncThemeFetcher { + + private final ExecutorService executorService; + private final TemplateThemeConfig config; + + public AsyncThemeFetcher(int threads, TemplateThemeConfig config) { + this.executorService = ModuleContext.getExecutor().newFixedThreadPool( + threads, + new NamedThreadFactory(this.getClass().getName()) + ); + this.config = config; + } + + public void shutdown() { + executorService.shutdown(); + } + + public boolean isShutdown() { + return executorService.isShutdown(); + } + + public void submit(String themeName, AsyncThemeFetchCallback callback) { + callback.beforeCachedFetch(); + executorService.submit(new Runnable() { + @Override + public void run() { + if (executorService.isShutdown()) { + return; + } + T theme = config.cachedFetch(themeName, new TemplateThemeConfig.CacheCondition() { + @Override + public boolean shouldCacheTheme(T theme) { + return callback.shouldCache(AsyncThemeFetcher.this, theme); + } + }); + if (executorService.isShutdown()) { + return; + } + callback.afterCachedFetch(theme); + } + }); + } + + public interface AsyncThemeFetchCallback { + void beforeCachedFetch(); + boolean shouldCache(AsyncThemeFetcher fetcher, T theme); + void afterCachedFetch(T theme); + } + + public static class AsyncThemeFetchCallbackAdapter implements AsyncThemeFetchCallback { + + @Override + public void beforeCachedFetch() { + + } + + @Override + public boolean shouldCache(AsyncThemeFetcher fetcher, T theme) { + // 如果Fetcher已经关闭就不放进缓存里了 + // 因为可切换工作目录,所以submit时的工作目录环境与最终获取到主题数据时的工作目录环境可能不是同一个, + // 如果仍然放进缓存中,会污染当前工作目录环境的主题缓存. + // TODO: 除了根据asyncThemeFetch的关闭情况来判断是否缓存主题,也可以更加精细的判断前后的工作目录环境是否时同一个 + // TODO: 后续看情况再优化吧. + return !fetcher.isShutdown(); + } + + @Override + public void afterCachedFetch(T theme) { + + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java index a61c2721e..b61cd9798 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeBlock.java @@ -55,16 +55,13 @@ public class TemplateThemeBlock extends JPanel { private boolean hovering = false; private MouseAdapter clickListener; - private final ExecutorService asyncThemeFetcher; public TemplateThemeBlock(String name, TemplateThemeConfig config, - TemplateThemeProfilePane profilePane, - ExecutorService asyncThemeFetcher) { + TemplateThemeProfilePane profilePane) { this.name = name; this.config = config; this.profilePane = profilePane; - this.asyncThemeFetcher = asyncThemeFetcher; initializePane(); addMouseListener(new MouseAdapter() { @@ -91,8 +88,6 @@ public class TemplateThemeBlock extends JPanel { repaint(); } }); - - fetchTheme(); } private void initializePane() { @@ -119,6 +114,21 @@ public class TemplateThemeBlock extends JPanel { add(infoPane, BorderLayout.SOUTH); } + public void setTheme(T theme) { + this.theme = theme; + thumbnailLabel.setIcon(null); + if (theme != null) { + ThemeThumbnail thumbnail = theme.getThumbnail(); + if (thumbnail != null) { + Image image = thumbnail.getImage(); + if (image != null) { + thumbnailLabel.setIcon(new ImageIcon(image)); + } + } + } + repaint(); + } + public T getTheme() { return this.theme; } @@ -166,48 +176,6 @@ public class TemplateThemeBlock extends JPanel { profileDialog.setVisible(true); } - public void fetchTheme() { - if (asyncThemeFetcher.isShutdown()) { - return; - } - asyncThemeFetcher.submit(new Runnable() { - @Override - public void run() { - if (asyncThemeFetcher.isShutdown()) { - return; - } - - theme = null; - // 耗时的同步操作,如远程设计器场景 - theme = config.cachedFetch(name, new TemplateThemeConfig.CacheCondition() { - @Override - public boolean shouldCacheTheme(T theme) { - // 如果Fetcher已经关闭就不放进缓存里了 - // 因为可切换工作目录,所以submit时的工作目录环境与最终获取到主题数据时的工作目录环境可能不是同一个, - // 如果仍然放进缓存中,会污染当前工作目录环境的主题缓存. - // TODO: 除了根据asyncThemeFetch的关闭情况来判断是否缓存主题,也可以更加精细的判断前后的工作目录环境是否时同一个 - // TODO: 后续看情况再优化吧. - return !asyncThemeFetcher.isShutdown(); - } - }); - - if (asyncThemeFetcher.isShutdown()) { - return; - } - if (theme != null) { - ThemeThumbnail thumbnail = theme.getThumbnail(); - if (thumbnail != null) { - Image image = thumbnail.getImage(); - if (image != null) { - thumbnailLabel.setIcon(new ImageIcon(image)); - } - } - } - repaint(); - } - }); - } - @Override public void paint(Graphics g) { super.paint(g); @@ -215,7 +183,7 @@ public class TemplateThemeBlock extends JPanel { if (template != null) { TemplateThemeConfig templateUsingConfig = template.getUsingTemplateThemeConfig(); TemplateTheme templateTheme = template.getTemplateTheme(); - if (templateUsingConfig == this.config && StringUtils.equals(templateTheme.getName(), theme.getName())) { + if (templateUsingConfig == this.config && StringUtils.equals(templateTheme.getName(), name)) { theme4currentTemplateMarkIcon.paintIcon(this, g, 176, 0); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeListPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeListPane.java index 403fde166..1b6eab40a 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeListPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeListPane.java @@ -2,14 +2,12 @@ package com.fr.design.mainframe.theme; import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.TemplateThemeConfig; -import com.fr.concurrent.NamedThreadFactory; import com.fr.design.designer.IntervalConstants; import com.fr.design.dialog.BasicPane; import com.fr.design.event.ChangeEvent; import com.fr.design.event.ChangeListener; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.module.ModuleContext; import com.fr.stable.StringUtils; import javax.swing.BorderFactory; @@ -22,7 +20,6 @@ import java.awt.event.MouseEvent; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutorService; /** * @author Starryi @@ -33,12 +30,9 @@ public class TemplateThemeListPane extends BasicPane { public static final int BLOCK_COUNT_ROW_LINE = 3; public static final int BLOCK_GAP = IntervalConstants.INTERVAL_L1; public static final int CONTENT_WIDTH = 630; + public static final int ASYNC_FETCH_THEME_THREAD_COUNT = 10; - private final ExecutorService asyncThemeFetcher = - ModuleContext.getExecutor().newFixedThreadPool( - 10, - new NamedThreadFactory("TemplateThemeListPane") - ); + private final AsyncThemeFetcher asyncThemeFetcher; protected final TemplateThemeConfig config; private final TemplateThemeProfilePane profilePane; @@ -57,6 +51,7 @@ public class TemplateThemeListPane extends BasicPane { this.config = config; this.profilePane = profilePane; this.contentListPane = new JPanel(); + this.asyncThemeFetcher = new AsyncThemeFetcher<>(ASYNC_FETCH_THEME_THREAD_COUNT, config); initializePane(); } @@ -100,7 +95,7 @@ public class TemplateThemeListPane extends BasicPane { } private TemplateThemeBlock createNewTemplateThemeBlock(String name) { - final TemplateThemeBlock block = new TemplateThemeBlock<>(name, config, profilePane, asyncThemeFetcher); + final TemplateThemeBlock block = new TemplateThemeBlock<>(name, config, profilePane); block.addClickListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -108,6 +103,19 @@ public class TemplateThemeListPane extends BasicPane { setSelectedBlock(block); } }); + asyncThemeFetcher.submit(name, new AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter() { + @Override + public void beforeCachedFetch() { + super.beforeCachedFetch(); + block.setTheme(null); + } + + @Override + public void afterCachedFetch(T theme) { + super.afterCachedFetch(theme); + block.setTheme(theme); + } + }); return block; } @@ -128,6 +136,10 @@ public class TemplateThemeListPane extends BasicPane { } } + private void asyncFetchTheme(String themeName) { + asyncThemeFetcher.submit(themeName, new AsyncThemeListItemFetchCallback(themeName)); + } + @Override protected String title4PopupWindow() { return null; @@ -142,21 +154,22 @@ public class TemplateThemeListPane extends BasicPane { themeConfigChangeListener = new TemplateThemeConfig.ThemeConfigChangeListener() { @Override public void onThemeConfigChanged(TemplateThemeConfig.ThemeConfigEvent event) { + String themeName = event.themName; TemplateThemeBlock existingBlock = blockCache.get(event.themName); switch (event.action) { case DEFAULT_THEME_4_NEW_TEMPLATE_UPDATE: { if (block4newTemplate != null) { - block4newTemplate.fetchTheme(); + block4newTemplate.repaint(); } if (existingBlock != null) { - existingBlock.fetchTheme(); + existingBlock.repaint(); } block4newTemplate = existingBlock; break; } case UPDATE: { if (existingBlock != null) { - existingBlock.fetchTheme(); + asyncFetchTheme(themeName); } break; } @@ -176,6 +189,7 @@ public class TemplateThemeListPane extends BasicPane { if (existingBlock == null) { // TODO 这里是否还能继续优化? fillContentListPane(); + asyncFetchTheme(themeName); validate(); repaint(); } @@ -198,4 +212,29 @@ public class TemplateThemeListPane extends BasicPane { public void stopAsyncFetchTheme() { asyncThemeFetcher.shutdown(); } + + private class AsyncThemeListItemFetchCallback extends AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter { + private final String themeName; + public AsyncThemeListItemFetchCallback(String themeName) { + this.themeName = themeName; + } + + @Override + public void beforeCachedFetch() { + super.beforeCachedFetch(); + TemplateThemeBlock block = blockCache.get(themeName); + if (block != null) { + block.setTheme(null); + } + } + + @Override + public void afterCachedFetch(T theme) { + super.afterCachedFetch(theme); + TemplateThemeBlock block = blockCache.get(themeName); + if (block != null) { + block.setTheme(theme); + } + } + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeManagePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeManagePane.java index cb0e4562d..0363bd88d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeManagePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeManagePane.java @@ -58,6 +58,8 @@ public class TemplateThemeManagePane extends BasicPane private final TemplateThemeListPane themeListPane; private final TemplateThemeProfilePane profilePane; + private final AsyncThemeFetcher asyncThemeFetcher; + public static TemplateThemeManagePane createFormThemesManagerPane() { FormThemeConfig config = FormThemeConfig.getInstance(); FormThemeProfilePane editPane = new FormThemeProfilePane(config); @@ -76,6 +78,7 @@ public class TemplateThemeManagePane extends BasicPane this.themeListPane = new TemplateThemeListPane<>(config, profilePane); this.removeAction = new RemoveThemeAction(false); this.setTheme4NewTemplateButton = new UIButton(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Default_Setting")); + this.asyncThemeFetcher = new AsyncThemeFetcher<>(1, config); initializePane(); } @@ -167,9 +170,9 @@ public class TemplateThemeManagePane extends BasicPane setTheme4NewTemplateButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - T style = themeListPane.getSelectedTheme(); - if (style != null) { - config.setThemeName4NewTemplate(style.getName()); + T theme = themeListPane.getSelectedTheme(); + if (theme != null) { + config.setThemeName4NewTemplate(theme.getName()); } } }); @@ -188,8 +191,8 @@ public class TemplateThemeManagePane extends BasicPane MenuDef menuDef = new MenuDef(Toolkit.i18nText("Fine-Design_Basic_Action_Add")); menuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH); menuDef.setRePaint(true); - menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Light_Theme"), config.cachedFetchLightTheme4New())); - menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Dark_Theme"), config.cachedFetchDarkTheme4New())); + menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Light_Theme"), config.getLightThemeName4New())); + menuDef.addShortCut(new AddThemeAction(Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Create_Dark_Theme"), config.getDarkThemeName4New())); return menuDef; } @@ -211,6 +214,9 @@ public class TemplateThemeManagePane extends BasicPane @Override public void actionPerformed(ActionEvent e) { T theme = TemplateThemeManagePane.this.themeListPane.getSelectedTheme(); + if (theme == null) { + return; + } int result = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this), Toolkit.i18nText("Fine-Design_Template_Theme_Manager_Pane_Delete_Tip", theme.getName()), Toolkit.i18nText("Fine-Design_Basic_Delete"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); @@ -226,20 +232,35 @@ public class TemplateThemeManagePane extends BasicPane } private class AddThemeAction extends UpdateAction { - private final T theme4New; + private T prototypeTheme; - public AddThemeAction(String name, T theme4New) { + public AddThemeAction(String name, String prototypeThemeName) { setName(name); setMnemonic('R'); - this.theme4New = theme4New; + asyncThemeFetcher.submit(prototypeThemeName, new AsyncThemeFetcher.AsyncThemeFetchCallbackAdapter() { + @Override + public void beforeCachedFetch() { + super.beforeCachedFetch(); + prototypeTheme = null; + } + + @Override + public void afterCachedFetch(T theme) { + super.afterCachedFetch(theme); + prototypeTheme = theme; + } + }); } @Override public void actionPerformed(ActionEvent e) { + if (prototypeTheme == null) { + return; + } Window parent = SwingUtilities.getWindowAncestor(TemplateThemeManagePane.this); TemplateThemeProfileDialog profileDialog = new TemplateThemeProfileDialog<>(parent, profilePane); try { - T theme = (T) theme4New.clone(); + T theme = (T) prototypeTheme.clone(); theme.setName(StringUtils.EMPTY); theme.setMutable(true); theme.setRemovable(true); @@ -285,6 +306,7 @@ public class TemplateThemeManagePane extends BasicPane } public void stopAsyncFetchTheme() { + asyncThemeFetcher.shutdown(); themeListPane.stopAsyncFetchTheme(); } } \ No newline at end of file