Skip to content

Instantly share code, notes, and snippets.

@evasyuk
Created October 19, 2015 14:55
Show Gist options
  • Save evasyuk/d629edde2d4c96ce75d7 to your computer and use it in GitHub Desktop.
Save evasyuk/d629edde2d4c96ce75d7 to your computer and use it in GitHub Desktop.
Android BUS pattern + utility gist
package com.genyware.core;
//missed
public class App extends Application implements Bus.Subscriber {
public static TManager tm;
private static App self;
public static App getInstance() {
return self;
}
@Override
public void onCreate() {
tm = TManager.getInstance();
// start service if not running
super.onCreate();
self = this;
}
}
package com.genyware.core;
import android.util.Log;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
public class Bus {
private ConcurrentMap<String, CopyOnWriteArrayList<Subscriber>> subscribers = new ConcurrentHashMap<String, CopyOnWriteArrayList<Subscriber>>();
public static final String TAG = "BUS -> ";
private static Bus instance;
private static final int MAX_TRY_COUNT = 50;
private static final int TRY_TIMEOUNT_MLS = 100;
private Bus() {
}
private void dispatch(final Event evt, final int count) {
try {
final String key = evt.getClass().getSimpleName();
List<Subscriber> subs = subscribers.get(key);
if (subs == null) {
// Log.v(TAG, "Not registered subscribers for event "+key+". Retry...");
App.tm.exec(new Runnable() {
@Override
public void run() {
if (count == MAX_TRY_COUNT) {
Log.v(TAG, "Not registered subscribers for event " + key + " after retry " + count + ". Event ignored");
post(new NotDeliveredEvent(evt));
} else {
try {
Thread.sleep(TRY_TIMEOUNT_MLS);
dispatch(evt, count + 1);
} catch (InterruptedException e) {
App.track(e);
}
}
}
});
} else {
// StringBuilder sb = new StringBuilder();
// for (Subscriber s : subs) sb.append(s.getClass().getSimpleName()).append(" ");
// Log.v(TAG, "Found subscribers for event " + key + ": " + sb);
for (final Subscriber s : subs) {
try {
Log.v(TAG, "Event " + key + " delivered to " + s.getClass().getSimpleName() + " successfully");
s.onEvent(evt);
// Log.v(TAG, "Event " + key + " processed into " + s.getClass().getSimpleName() + " successfully");
} catch (Exception e) {
App.track(e);
}
}
}
} catch (Exception e) {
App.track(e);
}
}
public static Bus getInstance() {
if (instance == null) instance = new Bus();
return instance;
}
public boolean register(Subscriber s, String evt) {
if (isRegistered(s, evt)) {
Log.v(TAG, "Subscriber " + s.getClass().getSimpleName() + " already subscribed on event " + evt);
return false;
}
CopyOnWriteArrayList<Subscriber> subs = subscribers.get(evt);
if (subs == null) subs = new CopyOnWriteArrayList<Subscriber>();
subs.add(s);
subscribers.put(evt, subs);
Log.v(TAG, "Subscriber " + s.getClass().getSimpleName() + " subscribed on event " + evt + " successfully");
return true;
}
public boolean unregister(Subscriber s, String evt) {
if (!isRegistered(s, evt)) {
Log.v(TAG, "Subscriber " + s.getClass().getSimpleName() + " already not subscribed on event " + evt);
return false;
}
CopyOnWriteArrayList<Subscriber> subs = subscribers.get(evt);
subs.remove(s);
if (subs.size() == 0) {
subscribers.remove(evt);
} else {
subscribers.put(evt, subs);
}
Log.v(TAG, "Subscriber " + s.getClass().getSimpleName() + " unregistered on event " + evt + " successfully");
return true;
}
public boolean unregister(Subscriber s) {
for (String key : subscribers.keySet()) {
CopyOnWriteArrayList<Subscriber> subs = subscribers.get(key);
if (!subs.contains(s)) continue;
subs.remove(s);
if (subs.size() == 0) {
subscribers.remove(key);
} else {
subscribers.put(key, subs);
}
}
Log.v(TAG, "Subscriber " + s.getClass().getSimpleName() + " unregistered on all events successfully");
return true;
}
public boolean isRegistered(Subscriber s, String evt) {
List<Subscriber> subs = subscribers.get(evt);
return subs != null && subs.contains(s);
}
public boolean isRegistered(String sName) {
for (String key : subscribers.keySet()) {
List<Subscriber> subs = subscribers.get(key);
for (Subscriber ss : subs) {
if (sName.equals(ss.getClass().getSimpleName())) return true;
}
}
return false;
}
public void post(final Event evt) {
App.tm.exec(new Runnable() {
@Override
public void run() {
Thread.currentThread().setName("Bus dispatcher");
dispatch(evt, 0);
}
});
}
public void postThisThread(final Event evt) {
dispatch(evt, 0);
}
//------------------------------
public interface Subscriber {
public void onEvent(Event evt);
}
public interface Event {
}
public class NotDeliveredEvent implements Event {
private Event event;
public NotDeliveredEvent(Event event) {
this.event = event;
}
public Event getEvent() {
return event;
}
}
}
package com.genyware.core;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TManager {
private static TManager instance;
ExecutorService pool;
private TManager() {
pool = Executors.newCachedThreadPool();
}
public static TManager getInstance() {
if (instance == null) instance = new TManager();
return instance;
}
public void exec(Runnable r) {
pool.execute(r);
}
public void end() {
pool.shutdown();
try {
if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(5, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
pool.shutdownNow();
Thread.currentThread().interrupt();
}
instance = null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment