diff --git a/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java index 378e5512a..a356a5b45 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java @@ -42,7 +42,7 @@ import butterknife.OnClick; import butterknife.Unbinder; public class MagiskFragment extends Fragment - implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView { + implements SwipeRefreshLayout.OnRefreshListener, ExpandableView, Topic.Subscriber { private Container expandableContainer = new Container(); @@ -167,8 +167,7 @@ public class MagiskFragment extends Fragment safetyNetStatusText.setText(R.string.safetyNet_check_text); - mm.safetyNetDone.reset(); - mm.updateCheckDone.reset(); + Topic.reset(getSubscribedTopics()); Data.remoteMagiskVersionString = null; Data.remoteMagiskVersionCode = -1; collapse(); @@ -184,17 +183,20 @@ public class MagiskFragment extends Fragment } @Override - public void onTopicPublished(Topic topic) { - if (topic == mm.updateCheckDone) { - updateCheckUI(); - } else if (topic == mm.safetyNetDone) { - updateSafetyNetUI((int) topic.getResults()[0]); - } + public int[] getSubscribedTopics() { + return new int[] {Topic.SNET_CHECK_DONE, Topic.UPDATE_CHECK_DONE}; } @Override - public Topic[] getSubscription() { - return new Topic[] { mm.updateCheckDone, mm.safetyNetDone }; + public void onPublish(int topic, Object[] result) { + switch (topic) { + case Topic.SNET_CHECK_DONE: + updateSafetyNetUI((int) result[0]); + break; + case Topic.UPDATE_CHECK_DONE: + updateCheckUI(); + break; + } } @Override diff --git a/app/src/full/java/com/topjohnwu/magisk/MagiskHideFragment.java b/app/src/full/java/com/topjohnwu/magisk/MagiskHideFragment.java index 679fe89e0..053624ee8 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MagiskHideFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/MagiskHideFragment.java @@ -80,13 +80,13 @@ public class MagiskHideFragment extends Fragment implements Topic.Subscriber { } @Override - public void onTopicPublished(Topic topic) { - mSwipeRefreshLayout.setRefreshing(false); - appAdapter.filter(null); + public int[] getSubscribedTopics() { + return new int[] {Topic.MAGISK_HIDE_DONE}; } @Override - public Topic[] getSubscription() { - return new Topic[] { getApplication().magiskHideDone }; + public void onPublish(int topic, Object[] result) { + mSwipeRefreshLayout.setRefreshing(false); + appAdapter.filter(null); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/MagiskManager.java b/app/src/full/java/com/topjohnwu/magisk/MagiskManager.java index d4847e25f..6f9ab9575 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MagiskManager.java +++ b/app/src/full/java/com/topjohnwu/magisk/MagiskManager.java @@ -10,7 +10,6 @@ import com.topjohnwu.magisk.database.MagiskDatabaseHelper; import com.topjohnwu.magisk.database.RepoDatabaseHelper; import com.topjohnwu.magisk.utils.LocaleManager; import com.topjohnwu.magisk.utils.RootUtils; -import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.superuser.ContainerApp; import com.topjohnwu.superuser.Shell; @@ -20,15 +19,6 @@ import java.util.Map; public class MagiskManager extends ContainerApp { - // Topics - public final Topic magiskHideDone = new Topic(); - public final Topic reloadActivity = new Topic(); - public final Topic moduleLoadDone = new Topic(); - public final Topic repoLoadDone = new Topic(); - public final Topic updateCheckDone = new Topic(); - public final Topic safetyNetDone = new Topic(); - public final Topic localeDone = new Topic(); - // Info public boolean hasInit = false; diff --git a/app/src/full/java/com/topjohnwu/magisk/MainActivity.java b/app/src/full/java/com/topjohnwu/magisk/MainActivity.java index c988d4e20..dc6ecf8f4 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MainActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/MainActivity.java @@ -111,13 +111,13 @@ public class MainActivity extends Activity } @Override - public void onTopicPublished(Topic topic) { - recreate(); + public int[] getSubscribedTopics() { + return new int[] {Topic.RELOAD_ACTIVITY}; } @Override - public Topic[] getSubscription() { - return new Topic[] { getMagiskManager().reloadActivity }; + public void onPublish(int topic, Object[] result) { + recreate(); } public void checkHideSection() { diff --git a/app/src/full/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/full/java/com/topjohnwu/magisk/ModulesFragment.java index 46f44c355..03c47dae7 100644 --- a/app/src/full/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/ModulesFragment.java @@ -4,6 +4,7 @@ import android.Manifest; import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; @@ -49,7 +50,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber { @Nullable @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_modules, container, false); unbinder = ButterKnife.bind(this, view); setHasOptionsMenu(true); @@ -71,19 +72,19 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber { } }); - getActivity().setTitle(R.string.modules); + requireActivity().setTitle(R.string.modules); return view; } @Override - public void onTopicPublished(Topic topic) { - updateUI(); + public int[] getSubscribedTopics() { + return new int[] {Topic.MODULE_LOAD_DONE}; } @Override - public Topic[] getSubscription() { - return new Topic[] { getApplication().moduleLoadDone }; + public void onPublish(int topic, Object[] result) { + updateUI(); } @Override diff --git a/app/src/full/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/full/java/com/topjohnwu/magisk/ReposFragment.java index 224d91085..b70f2aaf4 100644 --- a/app/src/full/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/ReposFragment.java @@ -46,7 +46,7 @@ public class ReposFragment extends Fragment implements Topic.Subscriber { unbinder = ButterKnife.bind(this, view); mm = getApplication(); - mSwipeRefreshLayout.setRefreshing(mm.repoLoadDone.isPending()); + mSwipeRefreshLayout.setRefreshing(true); mSwipeRefreshLayout.setOnRefreshListener(() -> { recyclerView.setVisibility(View.VISIBLE); @@ -73,15 +73,15 @@ public class ReposFragment extends Fragment implements Topic.Subscriber { } @Override - public void onTopicPublished(Topic topic) { - mSwipeRefreshLayout.setRefreshing(false); - recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE); - emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + public int[] getSubscribedTopics() { + return new int[] {Topic.REPO_LOAD_DONE}; } @Override - public Topic[] getSubscription() { - return new Topic[] { mm.repoLoadDone }; + public void onPublish(int topic, Object[] result) { + mSwipeRefreshLayout.setRefreshing(false); + recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE); + emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); } @Override diff --git a/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java index bbc06a506..ae6c5f75d 100644 --- a/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/SettingsActivity.java @@ -73,17 +73,18 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { } @Override - public void onTopicPublished(Topic topic) { - recreate(); + public int[] getSubscribedTopics() { + return new int[] {Topic.RELOAD_ACTIVITY}; } @Override - public Topic[] getSubscription() { - return new Topic[] { getMagiskManager().reloadActivity }; + public void onPublish(int topic, Object[] result) { + recreate(); } public static class SettingsFragment extends PreferenceFragmentCompat - implements SharedPreferences.OnSharedPreferenceChangeListener, Topic.Subscriber { + implements SharedPreferences.OnSharedPreferenceChangeListener, + Topic.Subscriber, Topic.AutoSubscriber { private SharedPreferences prefs; private PreferenceScreen prefScreen; @@ -229,14 +230,14 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { prefs.registerOnSharedPreferenceChangeListener(this); - subscribeTopics(); + Topic.subscribe(this); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onDestroyView() { prefs.unregisterOnSharedPreferenceChangeListener(this); - unsubscribeTopics(); + Topic.unsubscribe(this); super.onDestroyView(); } @@ -246,7 +247,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { switch (key) { case Const.Key.DARK_THEME: Data.isDarkTheme = prefs.getBoolean(key, false); - mm.reloadActivity.publish(false); + Topic.publish(false, Topic.RELOAD_ACTIVITY); return; case Const.Key.COREONLY: if (prefs.getBoolean(key, false)) { @@ -283,7 +284,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { break; case Const.Key.LOCALE: LocaleManager.setLocale(); - mm.reloadActivity.publish(false); + Topic.publish(false, Topic.RELOAD_ACTIVITY); break; case Const.Key.UPDATE_CHANNEL: new CheckUpdates().exec(); @@ -314,13 +315,13 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { } @Override - public void onTopicPublished(Topic topic) { + public void onPublish(int topic, Object[] result) { setLocalePreference((ListPreference) findPreference(Const.Key.LOCALE)); } @Override - public Topic[] getSubscription() { - return new Topic[] { mm.localeDone }; + public int[] getSubscribedTopics() { + return new int[] {Topic.LOCAL_FETCH_DONE}; } } diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java index bf2e5f060..0ce220a56 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java @@ -16,6 +16,7 @@ import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.Data; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.asyncs.ParallelTask; +import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.superuser.Shell; import java.util.ArrayList; @@ -152,7 +153,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter { Class.class, String.class, Activity.class, Object.class) .invoke(null, ISafetyNetHelper.class, dexPath.getPath(), getActivity(), (ISafetyNetHelper.Callback) code -> - Data.MM().safetyNetDone.publish(false, code)); + Topic.publish(false, Topic.SNET_CHECK_DONE, code)); if (helper.getVersion() != Const.SNET_VER) { throw new Exception(); } @@ -79,7 +80,7 @@ public class CheckSafetyNet extends ParallelTask { helper.attest(); } else { e.printStackTrace(); - Data.MM().safetyNetDone.publish(false, -1); + Topic.publish(false, Topic.SNET_CHECK_DONE, -1); } super.onPostExecute(e); } diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java b/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java index 3b1017ad8..b06e5b675 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java +++ b/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java @@ -5,6 +5,7 @@ import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.Data; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.utils.NotificationMgr; +import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.WebService; import org.json.JSONException; @@ -93,7 +94,6 @@ public class CheckUpdates extends ParallelTask { @Override protected void onPostExecute(Void v) { - MagiskManager mm = Data.MM(); if (showNotification) { if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) { NotificationMgr.managerUpdate(); @@ -101,7 +101,7 @@ public class CheckUpdates extends ParallelTask { NotificationMgr.magiskUpdate(); } } - mm.updateCheckDone.publish(); + Topic.publish(Topic.UPDATE_CHECK_DONE); super.onPostExecute(v); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/LoadModules.java b/app/src/full/java/com/topjohnwu/magisk/asyncs/LoadModules.java index 820054706..46e4d51a3 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/LoadModules.java +++ b/app/src/full/java/com/topjohnwu/magisk/asyncs/LoadModules.java @@ -5,6 +5,7 @@ import com.topjohnwu.magisk.Data; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.container.Module; import com.topjohnwu.magisk.container.ValueSortedMap; +import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.superuser.io.SuFile; public class LoadModules extends ParallelTask { @@ -29,7 +30,7 @@ public class LoadModules extends ParallelTask { @Override protected void onPostExecute(Void v) { - Data.MM().moduleLoadDone.publish(); + Topic.publish(Topic.MODULE_LOAD_DONE); super.onPostExecute(v); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java b/app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java index bd86395c1..8e507ce3e 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java +++ b/app/src/full/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java @@ -9,6 +9,7 @@ import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.ReposFragment; import com.topjohnwu.magisk.container.Repo; import com.topjohnwu.magisk.utils.Logger; +import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebService; @@ -49,8 +50,8 @@ public class UpdateRepos extends ParallelTask { private ExecutorService threadPool; public UpdateRepos(boolean force) { + Topic.reset(Topic.REPO_LOAD_DONE); mm = Data.MM(); - mm.repoLoadDone.reset(); forceUpdate = force; threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE); } @@ -147,11 +148,6 @@ public class UpdateRepos extends ParallelTask { ReposFragment.adapter.notifyDBChanged(); } - @Override - protected void onPreExecute() { - mm.repoLoadDone.setPending(); - } - @Override protected Void doInBackground(Void... voids) { etags = Arrays.asList(mm.prefs.getString(Const.Key.ETAG_KEY, "").split(",")); @@ -186,7 +182,7 @@ public class UpdateRepos extends ParallelTask { @Override protected void onPostExecute(Void v) { - mm.repoLoadDone.publish(); + Topic.publish(Topic.REPO_LOAD_DONE); super.onPostExecute(v); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java b/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java index 5ebd80b59..af643d0eb 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java @@ -14,9 +14,10 @@ import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.utils.LocaleManager; import com.topjohnwu.magisk.utils.Topic; -public abstract class FlavorActivity extends AppCompatActivity { +public abstract class FlavorActivity extends AppCompatActivity implements Topic.AutoSubscriber { private ActivityResultListener activityResultListener; + static int[] EMPTY_INT_ARRAY = new int[0]; public FlavorActivity() { super(); @@ -25,6 +26,11 @@ public abstract class FlavorActivity extends AppCompatActivity { applyOverrideConfiguration(configuration); } + @Override + public int[] getSubscribedTopics() { + return EMPTY_INT_ARRAY; + } + @StyleRes public int getDarkTheme() { return -1; @@ -37,9 +43,7 @@ public abstract class FlavorActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (this instanceof Topic.Subscriber) { - ((Topic.Subscriber) this).subscribeTopics(); - } + Topic.subscribe(this); if (Data.isDarkTheme && getDarkTheme() != -1) { setTheme(getDarkTheme()); } @@ -47,9 +51,7 @@ public abstract class FlavorActivity extends AppCompatActivity { @Override protected void onDestroy() { - if (this instanceof Topic.Subscriber) { - ((Topic.Subscriber) this).unsubscribeTopics(); - } + Topic.unsubscribe(this); super.onDestroy(); } diff --git a/app/src/full/java/com/topjohnwu/magisk/components/Fragment.java b/app/src/full/java/com/topjohnwu/magisk/components/Fragment.java index 59174d33a..ded53aae6 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/Fragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/Fragment.java @@ -6,7 +6,7 @@ import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; -public class Fragment extends android.support.v4.app.Fragment { +public class Fragment extends android.support.v4.app.Fragment implements Topic.AutoSubscriber { public MagiskManager getApplication() { return Utils.getMagiskManager(getActivity()); @@ -15,16 +15,12 @@ public class Fragment extends android.support.v4.app.Fragment { @Override public void onResume() { super.onResume(); - if (this instanceof Topic.Subscriber) { - ((Topic.Subscriber) this).subscribeTopics(); - } + Topic.subscribe(this); } @Override public void onPause() { - if (this instanceof Topic.Subscriber) { - ((Topic.Subscriber) this).unsubscribeTopics(); - } + Topic.unsubscribe(this); super.onPause(); } @@ -40,4 +36,9 @@ public class Fragment extends android.support.v4.app.Fragment { public void runWithPermission(String[] permissions, Runnable callback) { ((Activity) requireActivity()).runWithPermission(permissions,callback); } + + @Override + public int[] getSubscribedTopics() { + return FlavorActivity.EMPTY_INT_ARRAY; + } } diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/LocaleManager.java b/app/src/full/java/com/topjohnwu/magisk/utils/LocaleManager.java index 77c5c51bc..66ff71b20 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/LocaleManager.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/LocaleManager.java @@ -87,7 +87,7 @@ public class LocaleManager { } @Override protected void onPostExecute(Void aVoid) { - Data.MM().localeDone.publish(); + Topic.publish(Topic.LOCAL_FETCH_DONE); } } } diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/Topic.java b/app/src/full/java/com/topjohnwu/magisk/utils/Topic.java index d174c576a..9112c1b28 100644 --- a/app/src/full/java/com/topjohnwu/magisk/utils/Topic.java +++ b/app/src/full/java/com/topjohnwu/magisk/utils/Topic.java @@ -1,99 +1,98 @@ package com.topjohnwu.magisk.utils; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; +import android.support.annotation.IntDef; + +import com.topjohnwu.magisk.Data; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashSet; +import java.util.Set; public class Topic { - private static final int NON_INIT = 0; - private static final int PENDING = 1; - private static final int PUBLISHED = 2; + public static final int MAGISK_HIDE_DONE = 0; + public static final int RELOAD_ACTIVITY = 1; + public static final int MODULE_LOAD_DONE = 2; + public static final int REPO_LOAD_DONE = 3; + public static final int UPDATE_CHECK_DONE = 4; + public static final int SNET_CHECK_DONE = 5; + public static final int LOCAL_FETCH_DONE = 6; - private int state = NON_INIT; - private List> subscribers; - private Object[] results; + @IntDef({MAGISK_HIDE_DONE, RELOAD_ACTIVITY, MODULE_LOAD_DONE, REPO_LOAD_DONE, + UPDATE_CHECK_DONE, SNET_CHECK_DONE, LOCAL_FETCH_DONE}) + @Retention(RetentionPolicy.SOURCE) + public @interface TopicID {} - public Topic() { - subscribers = new SyncArrayList<>(); - } + // We will not dynamically add topics, so use arrays instead of hash tables + private static Store[] topicList = new Store[7]; - public synchronized void subscribe(Subscriber sub) { - subscribers.add(new WeakReference<>(sub)); - } - - public synchronized void unsubscribe() { - subscribers = new SyncArrayList<>(); - } - - public synchronized void unsubscribe(Subscriber sub) { - List> subs = subscribers; - subscribers = new ArrayList<>(); - for (WeakReference subscriber : subs) { - if (subscriber.get() != null && subscriber.get() != sub) - subscribers.add(subscriber); + public static void subscribe(Subscriber sub, @TopicID int... topics) { + for (int topic : topics) { + if (topicList[topic] == null) + topicList[topic] = new Store(); + topicList[topic].subscribers.add(sub); + if (topicList[topic].published) { + sub.onPublish(topic, topicList[topic].results); + } } } - public void reset() { - state = NON_INIT; - results = null; + public static void subscribe(AutoSubscriber sub) { + if (sub instanceof Subscriber) + subscribe((Subscriber) sub, sub.getSubscribedTopics()); } - public boolean isPublished() { - return state == PUBLISHED; - } - - public void publish() { - publish(true); - } - - public void publish(boolean record, Object... results) { - if (record) - state = PUBLISHED; - this.results = results; - // Snapshot - List> subs = subscribers; - for (WeakReference subscriber : subs) { - if (subscriber != null && subscriber.get() != null) - subscriber.get().onTopicPublished(this); + public static void unsubscribe(Subscriber sub, @TopicID int... topics) { + for (int topic : topics) { + if (topicList[topic] == null) + continue; + topicList[topic].subscribers.remove(sub); } } - public Object[] getResults() { - return results; + public static void unsubscribe(AutoSubscriber sub) { + if (sub instanceof Subscriber) + unsubscribe((Subscriber) sub, sub.getSubscribedTopics()); } - public boolean isPending() { - return state == PENDING; + public static void publish(@TopicID int topic, Object... results) { + publish(true, topic, results); } - public void setPending() { - state = PENDING; + public static void publish(boolean persist, @TopicID int topic, Object... results) { + if (topicList[topic] == null) + topicList[topic] = new Store(); + if (persist) { + topicList[topic].results = results; + topicList[topic].published = true; + } + for (Subscriber sub : topicList[topic].subscribers) { + Data.mainHandler.post(() -> sub.onPublish(topic, results)); + } + } + + public static void reset(@TopicID int... topics) { + for (int topic : topics) { + if (topicList[topic] == null) + continue; + topicList[topic].published = false; + topicList[topic].results = null; + } + } + + private static class Store { + boolean published = false; + Set subscribers = new HashSet<>(); + Object[] results; } public interface Subscriber { - default void subscribeTopics() { - for (Topic topic : getSubscription()) { - if (topic.isPublished()) { - onTopicPublished(topic); - } - topic.subscribe(this); - } - } - default void unsubscribeTopics() { - for (Topic event : getSubscription()) { - event.unsubscribe(this); - } - } - void onTopicPublished(Topic topic); - Topic[] getSubscription(); + void onPublish(int topic, Object[] result); } - private static class SyncArrayList extends ArrayList { - @Override - public synchronized boolean add(E e) { - return super.add(e); - } + public interface AutoSubscriber { + @TopicID + int[] getSubscribedTopics(); } }