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.
Related
How can I change the value of a variable inside the method from anonymous inner class, to access this variable it must be a final, but if the variable final can't change its value, how solve this problem using java?
This is My Code, I want to change the value of addFlag.
public static boolean addUser(UserModle user){
Boolean addFlag ;
dbUser = FirebaseDatabase.getInstance().getReference("user");
Task task = dbUser.child(user.getId()).setValue(user);
task.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
addFlag = true;
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
return addFlag;
}
IMHO, the current implementation of the addUser function is flawed. As per my understanding, you want to know if the user was added successfully to your firebase database based on the addFlag value that is returned from this function.
The addFlag will be updated once the Firebase database call will get back the data from the firebase realtime database. However, you are returning the flag immediately and hence you are not waiting for the result from your background network thread.
In order to achieve that, I would like to suggest an interface based implementation. You might have an interface as follows.
public interface FirebaseListener {
void onSuccess(boolean flag);
}
Then add an extra parameter in your addUser function to pass that interface from your Activity or Fragment where you are calling this function. Hence the function might look as follows.
// Change the return type to void, as we are not expecting anything from this function.
// Instead, we will wait for the success callback using the interface
public static void addUser(UserModle user, FirebaseListener listener) {
dbUser = FirebaseDatabase.getInstance().getReference("user");
Task task = dbUser.child(user.getId()).setValue(user);
task.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
listener.onSuccess(true);
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
listener.onSuccess(false);
}
});
}
Now implement the listener in your activity or fragment as follows.
public MyActivity extends AppCompatActivity implements FirebaseListener {
// ... Other functions of your activity
#Override
public void onSuccess(boolean flag) {
if (flag) {
// User add successful. Do something here
} else {
// User add not successful. Do something here
}
}
}
Now while calling the addUser function, you should pass the callback listener along with it as follows.
addUser(user, this);
I hope that helps.
I have method save. It saves entity using service which returns me com.google.common.util.concurrent.ListenableFuture<Void>. In case of fail I want to repeat save. I have next code for it:
public void save(Entity entity) {
ListenableFuture<Void> result = service.save(entity);
Futures.addCallback(result, new FutureCallback<Result>() {
#Override
public void onSuccess(Result callbackResult)
{
//do nothing
}
#Override
public void onFailure(Throwable throwable)
{
//some actions
save(entity);
}
});
}
But code above can be cause of StackOverflowException. If future will be done before addCallback then it will be recursive call. How can I optimize this code to remove recursion from it?
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 using a complex closed api. I want to create a super simple way to use it.
Basicaly, it has the following behaviour:
boolean everythingReady = false;
API.start(new Callback() {
public void onReady()
{
API.invite(new Callback2() {
public void onReady()
{
everythingReady = true;
}
});
}
});
while (!everythingReady); // Wait
API.send("hello);
API.send("What's up");
This is a chat API and the above code is "pseudo" java.
What I want to do now is:
API.start();
API.invite();
API.send("Hello);
API.send("What's up");
these methods would wait until each above has been correctly loaded (onReady called) to run. (eg: if (!apiStarted) addToQueue else do invite)
Is there a way to do that in java (as I can't edit at all the API sources).
Thanks
How about:
API.start(new Callback() {
public void onReady()
{
API.invite(new Callback() {
public void onReady()
{
API.send("hello");
API.send("What's up");
}
});
}
});
This way the send methods will be called only after invite is ready.
I am trying to understand mechanism of callback handler. How is the handle() method invoked? Can anybody give an example of usage of custom callback handler (other than those used in Login Modules of JASS or so) in non Swing application?
Define an interface to handle the callback.
public interface ServiceListener<T> {
void callback(T result);
}
Define a method that takes ServiceListener as parameter and returns void.
Public void runInBackground(ServiceListener listener) {
...code that runs in the background...
listener.callback(...data to return to caller...);
}
And you can now do this from your main code:
runInBackground(new ServiceListener() {
#Override
public void callback(..returned data...) {
...Do stuff with returned data...
}
});
This is a basic example for requesting data from a webserver using the AsyncTask from an Android application.
First define the async class. Note that the constructor takes a listener which we use to publish the result once ready.
public class Webservice extends AsyncTask<String, Void, String> {
private DialogListener dialogListener;
public Webservice(final DialogListener dialogListener) {
this.dialogListener = dialogListener;
}
#Override
protected String doInBackground(final String... strings) {
// We cant trigger onComplete here as we are not on the GUI thread!
return "";
}
protected void onPostExecute(final String result) {
dialogListener.onComplete(result);
}
}
Basic server class for handling various network communications:
public class Server {
public void queryServer(final String url, final DialogListener service) {
// Simulate slow network...
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Webservice(service).execute(url);
}
}
We can now use this code inside our activity without having to worry how long the call takes as it is not going to halt the GUI as it is executed async.
Server s = new Server();
// Async server call.
s.queryServer("http://onto.dk/actions/searchEvents.jsp?minLatE6=55640596&minLngE6=12078516&maxLatE6=55642654&maxLngE6=12081948", new DialogListener() {
#Override
public void onComplete(final String result) {
toast("complete");
}
#Override
public void onError() {
toast("error");
}
});