diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/MinecraftLoader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/MinecraftLoader.java index 09ee18248..a51dd99e7 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/MinecraftLoader.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/launch/MinecraftLoader.java @@ -38,6 +38,7 @@ import org.jackhuang.hellominecraft.launcher.version.MinecraftVersion; import org.jackhuang.hellominecraft.tasks.TaskWindow; import org.jackhuang.hellominecraft.utils.system.FileUtils; import org.jackhuang.hellominecraft.utils.MessageBox; +import rx.concurrency.Schedulers; /** * @@ -79,10 +80,10 @@ public class MinecraftLoader extends AbstractMinecraftLoader { if (!checkAssetsExist()) if (MessageBox.Show(C.i18n("assets.no_assets"), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) - IAssetsHandler.ASSETS_HANDLER.getList(version, provider, (value) -> { - if (value != null) - TaskWindow.getInstance().addTask(IAssetsHandler.ASSETS_HANDLER.getDownloadTask(dt.getProvider())).start(); - }); + IAssetsHandler.ASSETS_HANDLER.getList(version, provider) + .subscribeOn(Schedulers.newThread()) + .observeOn(Schedulers.eventQueue()) + .subscribe((value) -> TaskWindow.getInstance().addTask(IAssetsHandler.ASSETS_HANDLER.getDownloadTask(dt.getProvider())).start()); String game_assets = reconstructAssets().getAbsolutePath(); diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Profile.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Profile.java index 104c30def..7862aebd5 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Profile.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/settings/Profile.java @@ -120,6 +120,7 @@ public final class Profile { public void setSelectedMinecraftVersion(String selectedMinecraftVersion) { this.selectedMinecraftVersion = selectedMinecraftVersion; + Settings.save(); } public String getGameDir() { diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsLoader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsLoader.java deleted file mode 100644 index 07d159242..000000000 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsLoader.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2013 huangyuhui - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hellominecraft.launcher.utils.assets; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.jackhuang.hellominecraft.HMCLog; -import org.jackhuang.hellominecraft.utils.EventHandler; -import org.jackhuang.hellominecraft.utils.MathUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -/** - * - * @author huangyuhui - */ -public class AssetsLoader extends Thread { - - Document doc; - Element root; - NodeList nodes; - public String uri; - ArrayList al; - public final EventHandler failedEvent = new EventHandler<>(this); - public final EventHandler> successEvent = new EventHandler<>(this); - - AssetsLoader(String uri) { - this.uri = uri; - } - - private Contents modifyContents(NodeList contents) { - Contents ret = new Contents(); - for (int i = 0; i < contents.getLength(); i++) { - Node result = contents.item(i); - if (result.getNodeType() == Node.ELEMENT_NODE) { - if (result.getNodeName().equalsIgnoreCase("Key")) - ret.key = result.getTextContent(); - if (result.getNodeName().equalsIgnoreCase("ETag")) - ret.eTag = result.getTextContent(); - if (result.getNodeName().equalsIgnoreCase("LastModified")) - ret.lastModified = result.getTextContent(); - if (result.getNodeName().equalsIgnoreCase("Size")) - ret.size = MathUtils.parseInt(result.getTextContent(), 0); - if (result.getNodeName().equalsIgnoreCase("StorageClass")) - ret.storageClass = result.getTextContent(); - } - } - return ret; - } - - @Override - public void run() { - Thread.currentThread().setName("AssetsLoader"); - al = new ArrayList<>(); - try { - HMCLog.log("AssetsLoader - Download begin."); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = factory.newDocumentBuilder(); - doc = db.parse(uri); - HMCLog.log("AssetsLoader - Download end and format begin."); - root = doc.getDocumentElement(); - nodes = root.getChildNodes(); - for (int i = 0; i < nodes.getLength(); i++) { - Node result = nodes.item(i); - if (result.getNodeType() == Node.ELEMENT_NODE && result.getNodeName().equals("Contents")) { - Contents c = modifyContents(result.getChildNodes()); - if (c.key != null) - al.add(c); - } - } - HMCLog.log("AssetsLoader - Format end."); - - successEvent.execute(al); - } catch (ParserConfigurationException | SAXException | IOException e) { - HMCLog.warn("AssetsLoader - Failed", e); - failedEvent.execute(e); - } - } - -} diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsMojangLoader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsMojangLoader.java index 853564775..954ad0a23 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsMojangLoader.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsMojangLoader.java @@ -32,8 +32,10 @@ import org.jackhuang.hellominecraft.utils.StrUtils; import org.jackhuang.hellominecraft.launcher.utils.MCUtils; import org.jackhuang.hellominecraft.launcher.utils.download.IDownloadProvider; import org.jackhuang.hellominecraft.launcher.version.MinecraftVersion; -import org.jackhuang.hellominecraft.utils.functions.Consumer; import org.jackhuang.hellominecraft.utils.VersionNumber; +import rx.Observable; +import rx.Observer; +import rx.subscriptions.Subscriptions; /** * @@ -46,58 +48,62 @@ public class AssetsMojangLoader extends IAssetsHandler { } @Override - public void getList(MinecraftVersion mv, IMinecraftProvider mp, final Consumer dl) { - if (mv == null) { - dl.accept(null); - return; - } - String assetsId = mv.assets == null ? "legacy" : mv.assets; - File assets = mp.getAssets(); - HMCLog.log("Get index: " + assetsId); - File f = IOUtils.tryGetCanonicalFile(new File(assets, "indexes/" + assetsId + ".json")); - if (!f.exists() && !MCUtils.downloadMinecraftAssetsIndex(assets, assetsId, Settings.getInstance().getDownloadSource())) { - dl.accept(null); - return; - } - - String result; - try { - result = FileUtils.readFileToString(f); - } catch (IOException ex) { - HMCLog.warn("Failed to read index json: " + f, ex); - dl.accept(null); - return; - } - if (StrUtils.isBlank(result)) { - HMCLog.err("Index json is empty, please redownload it!"); - dl.accept(null); - return; - } - AssetsIndex o; - try { - o = C.gson.fromJson(result, AssetsIndex.class); - } catch (Exception e) { - HMCLog.err("Failed to parse index json, please redownload it!", e); - dl.accept(null); - return; - } - assetsDownloadURLs = new ArrayList<>(); - assetsLocalNames = new ArrayList<>(); - ArrayList al = new ArrayList<>(); - contents = new ArrayList<>(); - if (o != null && o.getFileMap() != null) - for (Map.Entry e : o.getFileMap().entrySet()) { - Contents c = new Contents(); - c.eTag = e.getValue().getHash(); - c.key = c.eTag.substring(0, 2) + "/" + e.getValue().getHash(); - c.size = e.getValue().getSize(); - contents.add(c); - assetsDownloadURLs.add(c.key); - assetsLocalNames.add(new File(assets, "objects" + File.separator + c.key.replace("/", File.separator))); - al.add(e.getKey()); + public Observable getList(MinecraftVersion mv, IMinecraftProvider mp) { + return Observable.create((Observer t1) -> { + if (mv == null) { + t1.onError(null); + return Subscriptions.empty(); + } + String assetsId = mv.assets == null ? "legacy" : mv.assets; + File assets = mp.getAssets(); + HMCLog.log("Get index: " + assetsId); + File f = IOUtils.tryGetCanonicalFile(new File(assets, "indexes/" + assetsId + ".json")); + if (!f.exists() && !MCUtils.downloadMinecraftAssetsIndex(assets, assetsId, Settings.getInstance().getDownloadSource())) { + t1.onError(null); + return Subscriptions.empty(); } - dl.accept(al.toArray(new String[1])); + String result; + try { + result = FileUtils.readFileToString(f); + } catch (IOException ex) { + HMCLog.warn("Failed to read index json: " + f, ex); + t1.onError(null); + return Subscriptions.empty(); + } + if (StrUtils.isBlank(result)) { + HMCLog.err("Index json is empty, please redownload it!"); + t1.onError(null); + return Subscriptions.empty(); + } + AssetsIndex o; + try { + o = C.gson.fromJson(result, AssetsIndex.class); + } catch (Exception e) { + HMCLog.err("Failed to parse index json, please redownload it!", e); + t1.onError(null); + return Subscriptions.empty(); + } + assetsDownloadURLs = new ArrayList<>(); + assetsLocalNames = new ArrayList<>(); + ArrayList al = new ArrayList<>(); + contents = new ArrayList<>(); + if (o != null && o.getFileMap() != null) + for (Map.Entry e : o.getFileMap().entrySet()) { + Contents c = new Contents(); + c.eTag = e.getValue().getHash(); + c.key = c.eTag.substring(0, 2) + "/" + e.getValue().getHash(); + c.size = e.getValue().getSize(); + contents.add(c); + assetsDownloadURLs.add(c.key); + assetsLocalNames.add(new File(assets, "objects" + File.separator + c.key.replace("/", File.separator))); + al.add(e.getKey()); + } + + t1.onNext(al.toArray(new String[1])); + t1.onCompleted(); + return Subscriptions.empty(); + }); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsMojangOldLoader.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsMojangOldLoader.java deleted file mode 100644 index a64067f78..000000000 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/AssetsMojangOldLoader.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2013 huangyuhui - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hellominecraft.launcher.utils.assets; - -import java.io.File; -import java.util.ArrayList; -import org.jackhuang.hellominecraft.HMCLog; -import org.jackhuang.hellominecraft.launcher.launch.IMinecraftProvider; -import org.jackhuang.hellominecraft.launcher.utils.download.IDownloadProvider; -import org.jackhuang.hellominecraft.launcher.version.MinecraftVersion; -import org.jackhuang.hellominecraft.utils.VersionNumber; -import org.jackhuang.hellominecraft.tasks.Task; -import org.jackhuang.hellominecraft.utils.functions.Consumer; -import rx.Observable; -import rx.util.functions.Func1; - -/** - * - * @author huangyuhui - */ -public class AssetsMojangOldLoader extends IAssetsHandler { - - private static final String URL = "http://bmclapi.bangbang93.com/resources/"; - - public AssetsMojangOldLoader(String name) { - super(name); - } - - @Override - public void getList(MinecraftVersion mv, IMinecraftProvider mp, final Consumer dl) { - AssetsLoader al = new AssetsLoader(URL); - al.failedEvent.register((sender, e) -> { - HMCLog.warn("Failed to get assets list.", e); - dl.accept(null); - return true; - }); - al.successEvent.register((sender, t) -> { - assetsDownloadURLs = new ArrayList<>(); - assetsLocalNames = new ArrayList<>(); - contents = t; - for (Contents c : t) { - assetsDownloadURLs.add(c.key); - assetsLocalNames.add(new File(mp.getAssets(), c.key.replace("/", File.separator))); - } - dl.accept(assetsDownloadURLs.toArray(new String[1])); - return true; - }); - new Thread(al).start(); - } - - @Override - public boolean isVersionAllowed(String formattedVersion) { - VersionNumber r = VersionNumber.check(formattedVersion); - if (r == null) - return false; - return VersionNumber.check("1.7.2").compareTo(r) >= 0 - && VersionNumber.check("1.6.0").compareTo(r) <= 0; - } - - @Override - public Task getDownloadTask(IDownloadProvider sourceType) { - return new AssetsTask(URL); - } -} diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/IAssetsHandler.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/IAssetsHandler.java index bfcc30b26..78e045c81 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/IAssetsHandler.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/utils/assets/IAssetsHandler.java @@ -34,6 +34,7 @@ import org.jackhuang.hellominecraft.utils.functions.Consumer; import org.jackhuang.hellominecraft.utils.code.DigestUtils; import org.jackhuang.hellominecraft.utils.system.IOUtils; import org.jackhuang.hellominecraft.utils.NetUtils; +import rx.Observable; /** * Assets @@ -73,7 +74,7 @@ public abstract class IAssetsHandler { * @param mp The Minecraft Provider * @param x finished event */ - public abstract void getList(MinecraftVersion mv, IMinecraftProvider mp, Consumer x); + public abstract Observable getList(MinecraftVersion mv, IMinecraftProvider mp); /** * Will be invoked when the user invoked "Download all assets". diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/version/MinecraftService.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/version/MinecraftService.java index 1ea1657d5..742797c83 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/version/MinecraftService.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/version/MinecraftService.java @@ -22,6 +22,7 @@ import org.jackhuang.hellominecraft.launcher.settings.Settings; import org.jackhuang.hellominecraft.launcher.utils.assets.IAssetsHandler; import org.jackhuang.hellominecraft.tasks.Task; import org.jackhuang.hellominecraft.tasks.TaskWindow; +import rx.concurrency.Schedulers; /** * @@ -41,10 +42,10 @@ public class MinecraftService { @Override public void executeTask() throws Throwable { IAssetsHandler type = IAssetsHandler.ASSETS_HANDLER; - type.getList(profile.getMinecraftProvider().getVersionById(mcVersion), profile.getMinecraftProvider(), (value) -> { - if (value != null) - TaskWindow.getInstance().addTask(type.getDownloadTask(Settings.getInstance().getDownloadSource().getProvider())).start(); - }); + type.getList(profile.getMinecraftProvider().getVersionById(mcVersion), profile.getMinecraftProvider()) + .subscribeOn(Schedulers.newThread()) + .observeOn(Schedulers.eventQueue()) + .subscribe((value) -> TaskWindow.getInstance().addTask(type.getDownloadTask(Settings.getInstance().getDownloadSource().getProvider())).start()); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/GameSettingsPanel.java b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/GameSettingsPanel.java index 5a095b033..2d25e7dcb 100644 --- a/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/GameSettingsPanel.java +++ b/HMCL/src/main/java/org/jackhuang/hellominecraft/launcher/views/GameSettingsPanel.java @@ -1142,7 +1142,6 @@ btnRefreshLiteLoader.addActionListener(new java.awt.event.ActionListener() { versionChanged(getProfile(), mcv); getProfile().setSelectedMinecraftVersion(mcv); cboVersions.setToolTipText(mcv); - Settings.save(); }//GEN-LAST:event_cboVersionsItemStateChanged private void btnRefreshVersionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshVersionsActionPerformed @@ -1154,12 +1153,7 @@ btnRefreshLiteLoader.addActionListener(new java.awt.event.ActionListener() { }//GEN-LAST:event_btnRefreshForgeActionPerformed private void btnDownloadForgeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDownloadForgeActionPerformed - int idx = lstForge.getSelectedRow(); - if (idx == -1) { - MessageBox.Show(C.i18n("install.not_refreshed")); - return; - } - profile.getInstallerService().downloadForge(forge.getVersion(idx)).after(new TaskRunnable(this::refreshVersions)).run(); + forge.downloadSelectedRow(); }//GEN-LAST:event_btnDownloadForgeActionPerformed private void btnRefreshOptifineActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshOptifineActionPerformed @@ -1167,21 +1161,11 @@ btnRefreshLiteLoader.addActionListener(new java.awt.event.ActionListener() { }//GEN-LAST:event_btnRefreshOptifineActionPerformed private void btnDownloadOptifineActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDownloadOptifineActionPerformed - int idx = lstOptifine.getSelectedRow(); - if (idx == -1) { - MessageBox.Show(C.i18n("install.not_refreshed")); - return; - } - profile.getInstallerService().downloadOptifine(optifine.getVersion(idx)).after(new TaskRunnable(this::refreshVersions)).run(); + optifine.downloadSelectedRow(); }//GEN-LAST:event_btnDownloadOptifineActionPerformed private void btnInstallLiteLoaderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnInstallLiteLoaderActionPerformed - int idx = lstLiteLoader.getSelectedRow(); - if (idx == -1) { - MessageBox.Show(C.i18n("install.not_refreshed")); - return; - } - profile.getInstallerService().downloadLiteLoader(liteloader.getVersion(idx)).after(new TaskRunnable(this::refreshVersions)).run(); + liteloader.downloadSelectedRow(); }//GEN-LAST:event_btnInstallLiteLoaderActionPerformed private void btnRefreshLiteLoaderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshLiteLoaderActionPerformed @@ -1608,8 +1592,8 @@ btnRefreshLiteLoader.addActionListener(new java.awt.event.ActionListener() { void refreshVersions() { list = Settings.getInstance().getDownloadSource().getProvider().getInstallerByType(id); if (TaskWindow.getInstance().addTask(new TaskRunnableArg1<>(C.i18n("install." + id + ".get_list"), list) - .registerPreviousResult(new DefaultPreviousResult<>(new String[] {getMinecraftVersionFormatted()}))) - .start()) + .registerPreviousResult(new DefaultPreviousResult<>(new String[] {getMinecraftVersionFormatted()}))) + .start()) loadVersions(); } @@ -1617,6 +1601,15 @@ btnRefreshLiteLoader.addActionListener(new java.awt.event.ActionListener() { return versions.get(idx); } + void downloadSelectedRow() { + int idx = jt.getSelectedRow(); + if (idx == -1) { + MessageBox.Show(C.i18n("install.not_refreshed")); + return; + } + profile.getInstallerService().downloadOptifine(getVersion(idx)).after(new TaskRunnable(this::refreshVersions)).run(); + } + private List loadVersions(InstallerVersionList list, JTable table) { if (list == null) return null; diff --git a/HMCLAPI/src/main/java/rx/concurrency/EventQueueScheduler.java b/HMCLAPI/src/main/java/rx/concurrency/EventQueueScheduler.java new file mode 100644 index 000000000..ed1db4370 --- /dev/null +++ b/HMCLAPI/src/main/java/rx/concurrency/EventQueueScheduler.java @@ -0,0 +1,38 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package rx.concurrency; + +import java.awt.EventQueue; +import java.util.concurrent.TimeUnit; +import rx.Subscription; +import rx.util.functions.Func0; + +/** + * + * @author huangyuhui + */ +public class EventQueueScheduler extends AbstractScheduler { + private static final EventQueueScheduler INSTANCE = new EventQueueScheduler(); + + public static EventQueueScheduler getInstance() { + return INSTANCE; + } + + @Override + public Subscription schedule(Func0 action) { + final DiscardableAction discardableAction = new DiscardableAction(action); + + EventQueue.invokeLater(discardableAction::call); + + return discardableAction; + } + + @Override + public Subscription schedule(Func0 action, long dueTime, TimeUnit unit) { + return schedule(new SleepingAction(action, this, dueTime, unit)); + } + +} diff --git a/HMCLAPI/src/main/java/rx/concurrency/Schedulers.java b/HMCLAPI/src/main/java/rx/concurrency/Schedulers.java index 1b27b9bf0..c24afb3ce 100644 --- a/HMCLAPI/src/main/java/rx/concurrency/Schedulers.java +++ b/HMCLAPI/src/main/java/rx/concurrency/Schedulers.java @@ -62,6 +62,15 @@ public class Schedulers { return NewThreadScheduler.getInstance(); } + /** + * {@link Scheduler} that queues work on the EventQueue thread to be executed on the Swing UI Thread. + * + * @return {@link NewThreadScheduler} instance + */ + public static Scheduler eventQueue() { + return EventQueueScheduler.getInstance(); + } + /** * {@link Scheduler} that queues work on an {@link Executor}. *

diff --git a/HMCLAPI/src/main/java/rx/subscriptions/Subscriptions.java b/HMCLAPI/src/main/java/rx/subscriptions/Subscriptions.java index 4c79ce7bf..b5f9a7689 100644 --- a/HMCLAPI/src/main/java/rx/subscriptions/Subscriptions.java +++ b/HMCLAPI/src/main/java/rx/subscriptions/Subscriptions.java @@ -21,14 +21,7 @@ public class Subscriptions { * @return {@link Subscription} */ public static Subscription create(final Action0 unsubscribe) { - return new Subscription() { - - @Override - public void unsubscribe() { - unsubscribe.call(); - } - - }; + return unsubscribe::call; } /** @@ -38,21 +31,11 @@ public class Subscriptions { */ public static Subscription create(final Object unsubscribe) { final FuncN f = Functions.from(unsubscribe); - return new Subscription() { - - @Override - public void unsubscribe() { - f.call(); - } - - }; + return f::call; } /** * A {@link Subscription} that does nothing when its unsubscribe method is called. */ - private static Subscription EMPTY = new Subscription() { - public void unsubscribe() { - } - }; + private static final Subscription EMPTY = () -> { }; }