I want to implement something like gate mechanism.
I need one PublishSubject and a couple of subscribers. When PublishSubject send data via onNext only one subscriber will receive it.
For example:
I have 3 equals fragments inside tabs. They have subscription to global published called onLoginPublisher.
When onResume or onPause called gate becomes open or closed.
When onLogin called and no gates are opened because of no one of these fragments on screen, onNext will wait for fragment's onResume
Look at the pic:
You can use filter with the gate's state. For example, you can wrap all the logic into a class:
public final class GatedSubject<T> {
final PublishSubject<T> subject = PublishSubject.create();
final AtomicReferenceArray<Boolean> gates;
public GatedSubject(int numGates) {
gates = new AtomicReferenceArray<>(numGates);
}
public boolean getGateStatus(int gateIndex) {
return gates.get(gateIndex) != null;
}
public void setGateStatus(int gateIndex, boolean status) {
gates.set(gateIndex, status ? Boolean.TRUE : null);
}
public void Observable<T> getGate(int gateIndex) {
return subject.filter(v -> getGateStatus(gateIndex));
}
public void onNext(T item) {
subject.onNext(item);
}
public void onError(Throwable error) {
subject.onError(error);
}
public void onComplete() {
subject.onComplete();
}
}
Related
The situation is I call an activity from my RouteActivity by:
arrived.observe(this, new Observer<Boolean>() {
#Override
public void onChanged(Boolean aBoolean) {
if(aBoolean==true){
Intent intent = new Intent(MyApplication.getAppContext(), RouteCompleteActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_up, R.anim.do_nothing);
finish();
}
}
});
That is fine then when I close the activity by calling:
Intent navIntent = new Intent(MyApplication.getAppContext(), NavigationStartActivity.class);
navIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(navIntent);
finish();
This takes me back to my main NavigationStartActivity, then when I again choose to go back to my RouteActivity the original, the RouteCompleteActivity is still over the top of it? so instead of RouteActivity I get RouteCompleteActivity then if I press back it goes to the RouteActivity?? as if it has remembered some backstack? can anyone explain this?
I assume that you're using a LiveData from a viewModel or repository which keeps its value. The case is like this: arrived has a true value and onChanged will be called. The next time RouteActivity observes arrived, onChanged will be called again because it already has a value and another startAcrivity will be called. A simple solution would be using SingleLiveEvent instead which was created by google long time ago link
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private final AtomicBoolean mPending = new AtomicBoolean(false);
#MainThread
public void observe(LifecycleOwner owner, final Observer<T> observer) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, new Observer<T>() {
#Override
public void onChanged(#Nullable T t) {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t);
}
}
});
}
#MainThread
public void setValue(#Nullable T t) {
mPending.set(true);
super.setValue(t);
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
#MainThread
public void call() {
setValue(null);
}
}
It simply calls onChange when a new value is set. I also recommend to take a look at this article which describes it deeper
I'm fairly new to RxJava and I have a basic understanding as to how to wrap a callback into an Observable but what I'm having difficulty with is doing so when the callback/listener is pre-instanced. Every example that I have found only shows instancing the callback directly into the Observable being created.
Some example code of what I'm talking about. I'm working with an Api that's works like this:
public class Api {
private ApiCallback callback;
void initialize(ApiCallback callback){
this.callback = callback;
}
void doAction1(){
this.callback.onAction1Complete();
}
}
interface ApiCallback {
void onInitialized();
void onAction1Complete();
}
With the real api I am working with I have no control over how it works so I must work with it in this state. In terms of trying to work with this Api using observables here is the struggle I am having. I have a member variable that holds the Api object:
private Api mApi = new Api();
Now in order to initialize this I have one of two options it seems.
Option 1:
Completable startApi() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
mApi.initialize(new ApiCallback() {
#Override
public void onInitialized() {
emitter.onComplete();
}
#Override
public void onAction1Complete() {
}
});
}
});
}
Option 2:
private ApiCallback premadeCallback = new ApiCallback() {
#Override
public void onInitialized() {
}
#Override
public void onAction1Complete() {
}
};
Completable startApi() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
mApi.initialize(premadeCallback);
}
});
}
Now the issue I have is that Option 2 makes more sense to me when I need to know when the other methods in the callback are called from Api calls. With my understanding of RxJava however I don't understand how I can reach these method calls with an Api that works like this.
For example:
Completable doAction1() {
return Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(final CompletableEmitter emitter) throws Exception {
// Api is already initialized with callback
// How do I reach the callback from here?
}
});
}
The only what that I can currently think of as to how to achieve this would be to create a member variable as an emitter (or a dictionary of emitters) and then call its appropriate method in the api callback when needed. My concerns with this are A. I'm unsure if RxJava can work this way B. This sounds like a terrible idea.
The below method onReceivedTitlegets called 2-3 times with in a second when webview url changes. I want to call a method in it, when onReceivedTitle is being called last time. I am doing this because I just want to monitor url changes with in webview. shouldOverrideUrlLoading is not getting called when url changes through ajax.
class MyWebChromeClient extends WebChromeClient {
#Override
public void onReceivedTitle(WebView view, String title) {
Log.v("onReceivedTitle", "=>" + title);
// callAMehod();
super.onReceivedTitle(view, title);
}
}
If you want to throttle how often a method call causes another method call you can do so for example via a Handler. The simplest version enqueues a delayed message on the first call and any subsequent call while there is an enqueued message will not enqueue a new one. That results in 1 call every X time to go though - but it take at least that amount of time until the first action happens.
Example implementation (you can put that class unmodified somewhere in your code)
public abstract class ThrottleExecutor {
private final long mMinDelay;
public ThrottleExecutor(long minDelay) {
mMinDelay = minDelay;
}
/** Implement to do something */
public abstract void doThrottled();
public final void scheduleExecution() {
if (mHandler.hasMessages(0)) {
// message already enqueued, do nothing
} else {
// otherwise enqueue a message for later
mHandler.sendEmptyMessageDelayed(0, mMinDelay);
}
}
public final void cancelExecution() {
mHandler.removeMessages(0);
}
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
doThrottled();
}
};
}
And then use it for example like so
class Usage {
private ThrottleExecutor mThrottle = new ThrottleExecutor(2000) {
#Override
public void doThrottled() {
// happens at most every 2000ms
methodToBeThrottled();
}
};
void methodThatHappensTooOften() {
mThrottle.scheduleExecution();
}
void methodToBeThrottled() {
Log.d("TAG", "triggered at 2000ms before");
}
}
You might want to use Handler and do something like this:
class MyWebChromeClient extends WebChromeClient {
private boolean mOnReceivedTitleInvoked;
#Override
public synchronized void onReceivedTitle(final WebView view, final String title) {
if (!mOnReceivedTitleInvoked) {
mOnReceivedTitleInvoked = true;
Log.v("onReceivedTitle", "=>" + title);
handler.postDelayed(new Runnable() {
#Override
public void run() {
super.onReceivedTitle(view, title);
mOnReceivedTitleInvoked = false;
}
}, 1000);
}
}
}
Although you might want to reconsider the onReceivedTitle behaviour.
I'm having a really bad time to implement a listener to a method.
In my current work i have to request a method every 5 seconds in order to verify for new information so i want to implement a method to notify me every time a new information come discarding the requesting method in every 5 seconds.
(I already read about observer pattern but had no successful in implementing.)
best regards
More information:
For now i m overriding this method from the smack XMPP library in order to store new messages in msgs Queue
public void processMessage(Chat chat, Message message) {
if (message.getType() == Message.Type.chat) {
req = message.getBody().toString();
String[] temp = { chat.getParticipant().toString(), req };
System.out.println(temp[0]+"says:"+temp[1]);
synchronized (lock) {
msgs.add(temp);
}
}
}
and than i have this method executed every 0.5 seconds in order to verify new messages:
public String[] getMessage() {
synchronized (lock) {
String[] data;
data=msgs.poll();
return data;
}
}
i'm trying to set a notification system that notifies me everytime the processMessage is executed.
Ok i manage to solve my problem.
I implemented a listener based on observer model. For that i had to implement a interface that i called XMPPmessageListener:
public interface XMPPmessageListener {
public void readMsg(String senderJID, String msg);
}
than in the XmppHandler class, the class of the methods processMessage and getMessage i added methods to add and remove listeners and a LinkedList to store the listeners:
private LinkedList<XMPPmessageListener> listeners = new LinkedList<XMPPmessageListener>();
public void addMsgListener(XMPPmessageListener listener){
listeners.add(listener);
}
public boolean removeMsgListener(XMPPmessageListener listener){
return listeners.remove(listener);
}
than i did some exchanges in processMessage method in order to warn the listeners:
public void processMessage(Chat chat, Message message) {
if (message.getType() == Message.Type.chat) {
for(XMPPmessageListener l: listeners){
l.readMsg(chat.getParticipant().toString(), message.getBody().toString());
}
}
}
Now i can be notified at any method everytime a message is receive by creating a XMPPmessageListener and decide what to do with the message by overriding the readMsg method:
XmppHandler xmpp = new XmppHandler(XMPPuser, XMPPpassword, XMPPaddress, XMPPdomain, XMPPport);
XMPPmessageListener msglistener = new XMPPmessageListener() {
#Override
public void readMsg(String senderJID, String msg) {
String asw=xmlHandler.processMsg(msg,senderJID);
}
};
xmpp.addMsgListener(msglistener);
I have a view that I want to react to what happens in the editor. Right now I have a button that I want it so that when clicked it updates the data in the view to some new set of information. Where do I start, I have my selection event but no idea on how to communicate between the two. I'm looking for a loose coupling solution.
I'm sure there are many ways of doing this, but I've used the JFace IPropertyChangeListener interface in the past for simple event propagation.
Make your view implement IPropertyChangeListener. Create a Singleton class that you can register your IPropertyChangeListener with, and send a PropertyChangeEvent to. Then in the constructor of your view, register it with your Singleton.
Now you can get hold of your Singleton in your editor and fire off an event that will get picked up in your view.
Example code for the Singleton:
public class PropertyChangeEventBus {
private static PropertyChangeEventBus s_instance = new PropertyChangeEventBus();
public static PropertyChangeEventBus instance()
{
return s_instance;
}
private Set<IPropertyChangeListener> m_listeners;
private PropertyChangeEventBus()
{
// use CopyOnWriteArraySet to prevent ConcurrentModificationExceptions
m_listeners = new CopyOnWriteArraySet<IPropertyChangeListener>();
}
public void addListener(IPropertyChangeListener listener)
{
m_listeners.add(listener);
}
public void removeListener(IPropertyChangeListener listener)
{
m_listeners.remove(listener);
}
public void fire(final PropertyChangeEvent event)
{
// run property change events in UI thread to prevent having to have lots of syncExecs in the listener methods
ViewUtils.syncExec(new Runnable()
{
#Override
public void run()
{
for (IPropertyChangeListener listener : m_listeners)
{
try
{
listener.propertyChange(event);
}
catch(Exception e)
{
//log it, present error message
}
}
}
});
}
}
Example Code for the View:
//The constructor
public MyView()
{
PropertyChangeEventBus.instance().addListener(this);
}
#Override
public void propertyChange(PropertyChangeEvent event)
{
if(event.getProperty().equals(SOME_CONSTANT))
{
// Refresh View
}
}