I have a problem with this async call:
public class myClass {
protected final int idObj;
public void myMethod() {
myService.getObj( new AsyncCallback<List<Object>>() {
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(List<Object> listObject) {
idObj = listObject.get(0).getIdObj();
}
});
if(idObj == 1) {
//do something
}
}
}
The value idObj is equal zero at the first time and this if block isn't execute.
How to avoid this?
It's an asynchronous call, that means that the code executed in your onSuccess method will be executed later.
So the if statement is executed but at this time your value still 0.
You should put your if statement in the onSuccess method.
Related
I'm using a SwingWorker to execute some repeatable tasks in background.
This is my Class:
public class CMyThread {
private SwingWorker<Object, Void> taskWorker;
public volatile boolean threadDone = false;
public CMyThread() {
}
#Override
public void stop() {
taskWorker.cancel(true);
}
#Override
public void start() {
taskWorker = new SwingWorker<Object, Void>() {
#Override
public Object doInBackground() {
while (!isCancelled()) {
// SOMETHING TIMECONSUMING THAT NEEDS TO BE DONE REPEATEDLY
CUtils.sleep(10000);
}
threadDone = true;
return null;
}
#Override
public void done() {
}
};
taskWorker.execute();
}
public void waitThreadToGentlyFinish() { // called when we call destroy() on the servlet
while (!threadDone) {
System.out.print("#");
CUtils.sleep(200);
}
}
}
And this is called this way:
CMyThread myThread = new CMyThread();
myThread.start();
Now, at one point I want to gently stop the thread.
So I call
myThread.stop();
myThread.waitThreadToGentlyFinish();
I'm expecting that the currently running [ACTION] is going to take time to finish, then only it will exit the loop and set the flag 'threadDone' to true. but what I actually see is that it exits the loop immediately and I never see any '#' characters displayed.
There is obviously something wrong in my code but I can't see the obvious.
Any idea guys ?
In RxJava2, here is my code:
public void myMethod() {
Flowable.create(e->{
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation())
.observeOn(Schedulers.io())
.subscribe(new Subscriber<ContentsWithChannelVO>() {
#Override
public void onSubscribe(Subscription subscription) { // do sth. }
#Override
public void onNext(ContentsWithChannelVO contentAndChannel) { // do sth. }
#Override
public void onError(Throwable throwable) { // do sth. }
#Override
public void onComplete() { // do sth. }
});
doSomething();
}
Here is a synchronized problem.
I want to know how to let my method wait for the flowable onComplete, that is to say doSomething() will be called after the flowable onCompleted.
I have searched for it but it doesn't help.
You can use concat operator, but you need to wrap your method in another observable.
Concat waits to subscribe to each additional Observable that you pass
to it until the previous Observable completes.
You'd have to block the consumption of the flow for that (which is generally not recommended):
public void myMethod() {
Flowable.create(e -> {
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation(), false)
.blockingSubscribe(new Subscriber<ContentsWithChannelVO>() {
#Override
public void onSubscribe(Subscription subscription) { // do sth. }
#Override
public void onNext(ContentsWithChannelVO contentAndChannel) { // do sth. }
#Override
public void onError(Throwable throwable) { // do sth. }
#Override
public void onComplete() { // do sth. }
});
doSomething();
}
In this case, having observeOn is pointless. Note also you have to use subscribeOn() with false otherwise the flow livelocks.
If you don't want to execute doSomething if the source fails, use blockingForEach:
public void myMethod() {
Flowable.create(e -> {
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation(), false)
.blockingForEach(contentAndChannel -> { /* do sth. */ });
doSomething();
}
Is there any way to get callback value out into main method.
public List<Passion> downloadpassion()
{
fsDB.getPassionvalue(new OnDownLoadPassionList() {
#Override
public List<Passion> OnResult(List<Passion> passionList) {
return passionList; //this is callback value
}
});
return passionList; //want passionList to pass here
}
you should make a interface like this
public interface EventListener{
void onListComplited(List<Passion> passionList)
}
and then add it as input for your function
public void downloadpassion(EventListener listener)
{
fsDB.getPassionvalue(new OnDownLoadPassionList() {
#Override
public List<Passion> OnResult(List<Passion> passionList) {
listener.onListComplited(passionList);
}
});
}
You can't return from a value within a callback.
Rewrite like this
public void downloadpassion(OnDownLoadPassionList onDownload) {
fsDB.getPassionvalue(onDownload);
}
In your other method
main() {
client.downloadpassion(new OnDownLoadPassionList() {
#Override
public List<Passion> OnResult(List<Passion> passionList) {
// TODO: use this callback value
}
});
}
The use case is there is a set of methods which need to be executed based on whether the previous one has returned true or not.
For example:
class Test {
boolean method1() {...}
boolean method2() {...}
boolean method3() {...}
...
void callAll() {
if(method1()) {
if(method2() {
if(method3() {
...
}
}
} else {
error();
}
}
}
There has to be an else for all the ifs.
Is there a better way of handling this scenario?
I would just do it like this:
void callAll(){
if(method1() && method2() && method3()){
// all passed
} else {
error();
}
}
Java short-circuits the && logical operation so failure in a previous method here will prevent running the next one.
If in error() you need to know which of the methods failed, you could declare an error message field for storing the information within the class and set its value corresponding the failure:
private String errorMessage;
//...
boolean method2() {
// something went wrong
errorMessage = "Failed to do method2 stuff";
}
Are more elegant way to achieve the same would be to use the Chain of responsibility design pattern and encapsulate the boolean methods in their own handler objects. Doing this would however require more refactoring to the code you currently have and more information about your specific use case.
It's easy enough to write your own varargs method to do this:
public static void run(Supplier<Boolean>... methods) {
for (Supplier<Boolean> method : methods) {
if (!method.get()) return;
}
}
Sample usage:
run(this::method1, this::method2, this::method3);
You can use some form of Observable pattern for these kind of thins too. In most normal cases it seems a bit silly to implement it but otherwise a great way to decouple code from control structures if you have a lot of these. Note that ObservableBoolean is an Android class, but just showing the logic here:
ObservableBoolean a = new ObservableBoolean();
ObservableBoolean b = new ObservableBoolean();
public void call() {
a.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
method2();
}
});
b.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
//..you end the "chain" here
}
});
method1();
}
void method1() {
if(true) {
a.set(true);
}
else {
b.set(false);
}
}
void method2() {
if(true) {
b.set(true);
}
else {
b.set(false);
}
}
I use this technique - although some would find it odd.
boolean method1() {
System.out.println("method1");
return true;
}
boolean method2() {
System.out.println("method2");
return false;
}
boolean method3() {
System.out.println("method3");
return true;
}
void callAll() {
boolean success = method1();
success = success ? method2() : success;
success = success ? method3() : success;
if (success) {
System.out.println("Success");
} else {
System.out.println("Failed");
}
}
I could suggest you to use RX approach, with rxjava it should look like
public boolean test1() {
Log.d("TESTIT", "test1 called");
return true;
}
public boolean test2() {
Log.d("TESTIT", "test2 called");
return true;
}
public boolean test3() {
Log.d("TESTIT", "test3 called");
return false;
}
public boolean test4() {
Log.d("TESTIT", "test4 called");
return true;
}
public boolean elseMethod(boolean result) {
if (result) return true;
else {
Log.d("TESTIT", "ELSE");
}
return false;
}
public void chainedCallback() {
Observable.just(test1())
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test2()))
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test3()))
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test4()))
.filter(this::elseMethod)
.subscribe();
}
call for chainedCallback() will print
test1 called
test2 called
test3 called
ELSE
You define a class that holds an action (calling one of the methods) and with a corresponding failure handler (the else block of an if call)
public static class ActionWithFailureHandler {
private Supplier<Boolean> action;
private Runnable failureHandler;
public ActionWithFailureHandler(Supplier<Boolean> action, Runnable failureHandler) {
this.action = action;
this.failureHandler = failureHandler;
}
//Getters for the instance variables
}
You make a list of the above and call each of the actions till one of the following happens
One of the actions fails (i.,e one of the method returns false). In that case, you need to execute the failureHandler corresponding to that action.
All actions pass. In this case, execute the successHandler (the logic that you execute when all methods return true).
private static void callAll(List<ActionWithFailureHandler> actionWithFailureHandlers, Runnable successHandler) {
actionWithFailureHandlers.stream()
.filter(actionWithFailureHandler -> !actionWithFailureHandler.getAction().get())
.findFirst() //Find first failing action
.map(ActionWithFailureHandler::getFailureHandler)
.orElse(successHandler)
.run(); //You might be running either the successHandler or the failureHandler for the first failed action
}
Driver code:
public static void main(String[] args) {
Test test = new Test();
List<ActionWithFailureHandler> actionWithFailureHandlers = com.google.common.collect.ImmutableList.of(
new ActionWithFailureHandler(test::method1, () -> System.out.println("Method 1 returned false")),
new ActionWithFailureHandler(test::method2, () -> System.out.println("Method 2 returned false")),
new ActionWithFailureHandler(test::method3, () -> System.out.println("Method 3 returned false"))
);
callAll(actionWithFailureHandlers, () -> System.out.println("All returned true"));
}
Exception firstly comes to my mind, but see the link below to learn more about its performance hit.
Original answer. I would do..
public class MyException extends Exception
{
}
public void doAll()
{
try
{
method1();
method2();
method3();
}catch (MyException e)
{
error();
}
}
And let's assume that method1, method2, and method3 throws MyException when it fails.
Though it does not fit your question, it is a good pattern to use Exceptions.
public class Helper
{
public Helper(Method m)
{
this.method=m;
}
public void Do() throws MyException
{
if(method.invoke()==false)
throw new MyException ();
}
}
Using this class,
public void doAll()
{
Helper [] helpers={new Helper(this::method1), new Helper(this::method2), new Helper (this::method3)};
try
{
for(Helper helper:helpers)
{
helper.Do();
}
}catch (MyException e)
{
error();
}
}
But
according to the comment of #dilix and the link, it can be a performance-expensive strategy.
So let's use them only for their purpose.
does anyone know how I can solve the following problem. I want to return a String from a callback, but I get only "The final local variable s cannot be assigned, since it is defined in an enclosing type", because of final.
public String getConstraint(int indexFdg) {
final String s;
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(String result) {
s = result;
}
};
SpeicherService.Util.getInstance().getConstraint(indexFdg, callback);
return s;
}
The whole point of an asynchronous callback is to notify you of something that happens asynchronously, at some time in the future. You can't return s from getConstraint if it's going to be set after the method has finished running.
When dealing with asynchronous callbacks you have to rethink the flow of your program. Instead of getConstraint returning a value, the code that would go on to use that value should be called as a result of the callback.
As a simple (incomplete) example, you would need to change this:
String s = getConstraint();
someGuiLabel.setText(s);
Into something like this:
myCallback = new AsyncCallback<String>() {
public void onSuccess(String result) {
someGuiLabel.setText(result);
}
}
fetchConstraintAsynchronously(myCallback);
Edit
A popular alternative is the concept of a future. A future is an object that you can return immediately but which will only have a value at some point in the future. It's a container where you only need to wait for the value at the point of asking for it.
You can think of holding a future as holding a ticket for your suit that is at the dry cleaning. You get the ticket immediately, can keep it in your wallet, give it to a friend... but as soon as you need to exchange it for the actual suit you need to wait until the suit is ready.
Java has such a class (Future<V>) that is used widely by the ExecutorService API.
An alternative workaround is to define a new class, called SyncResult
public class SyncResult {
private static final long TIMEOUT = 20000L;
private String result;
public String getResult() {
long startTimeMillis = System.currentTimeMillis();
while (result == null && System.currentTimeMillis() - startTimeMillis < TIMEOUT) {
synchronized (this) {
try {
wait(TIMEOUT);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return result;
}
public void setResult(String result) {
this.result = result;
synchronized (this) {
notify();
}
}
}
Then change your code to this
public String getConstraint(int indexFdg) {
final SyncResult syncResult = new SyncResult();
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
public void onSuccess(String result) {
syncResult.setResult(result);
}
};
SpeicherService.Util.getInstance().getConstraint(indexFdg, callback);
return syncResult.getResult();
}
The getResult() method will be blocked until setResult(String) method been called or the TIMEOUT reached.