I have this method and the first log prints, the others don't
What am I doing wrong?
That is this :Log.d("insideGetFriends","in"); Gets printed and I looked in my log,
Log.d("facebookError",Integer.toString(graphUsers.size())); and the remaining lines do not get executed.
public ArrayList<ParseUser> getFriends(Session session)
{
Log.d("insideGetFriends","in");
final ArrayList<ParseUser> users=new ArrayList<>();
Request.newMyFriendsRequest(session,new Request.GraphUserListCallback() {
#Override
public void onCompleted(List<GraphUser> graphUsers, Response response) {
Log.d("facebookError",Integer.toString(graphUsers.size()));
for(GraphUser user:graphUsers)
{
String facebookId=user.getId();
Log.d("facebookFriend",facebookId);
ParseQuery<ParseUser> query=ParseUser.getQuery();
query.whereEqualTo("facebookID",facebookId);
query.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> parseUsers, ParseException e) {
users.add(parseUsers.get(0));
}
});
}
}
});
return users;
}
It looks like you are not starting/executing the request.
You need to store the result of Request.newMyFriendsRequest(...) in a variable and then call .executeAsync() on it.
This is explained here: https://developers.facebook.com/docs/android/graph#userdata
Related
I am switching from async tasks to rxjava2 and have some issues with my code tests.
I have a room table of elements that have a certain monetary amount. On a usercontrol that is called DisplayCurrentBudget, a sum of all amounts should be displayed. This number must refresh everytime a new element is inserted. I tackled the requirement in two ways, but both produce the same result: My code does not care if the database is updated, it only updates when the fragment is recreated (onCreateView).
My first attempt was this:
//RxJava2 Test
Observable<ItemS> ItemObservable = Observable.create( emitter -> {
try {
List<ItemS> movies = oStandardModel.getItemsVanilla();
for (ItemS movie : movies) {
emitter.onNext(movie);
}
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
});
DisposableObserver<ItemS> disposable = ItemObservable.
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribeWith(new DisposableObserver<ItemS>() {
public List<ItemS> BadFeelingAboutThis = new ArrayList<ItemS>();
#Override
public void onNext(ItemS movie) {
// Access your Movie object here
BadFeelingAboutThis.add(movie);
}
#Override
public void onError(Throwable e) {
// Show the user that an error has occurred
}
#Override
public void onComplete() {
// Show the user that the operation is complete
oBinding.DisplayCurrentBudget.setText(Manager.GetBigSum(BadFeelingAboutThis).toString());
}
});
I already was uncomfortable with that code. My second attempt produces the exact same result:
Observable<BigDecimal> ItemObservable2 = Observable.create( emitter -> {
try {
BigDecimal mySum = oStandardModel.getWholeBudget();
emitter.onNext(mySum);
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
});
DisposableObserver<BigDecimal> disposable = ItemObservable2.
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribeWith(new DisposableObserver<BigDecimal>() {
#Override
public void onNext(BigDecimal sum) {
// Access your Movie object here
oBinding.DisplayCurrentBudget.setText(sum.toString());
}
#Override
public void onError(Throwable e) {
// Show the user that an error has occurred
}
#Override
public void onComplete() {
// Show the user that the operation is complete
}
});
Any obvious issues with my code?
Thanks for reading, much appreciate it!
Edit:
I was asked what Manager.GetBigSum does, it actually does not do much. It only adds BigDecimal-Values of an Item list.
public static BigDecimal GetBigSum(List<ItemS> ListP){
List<BigDecimal> bigDList = ListP.stream().map(ItemS::get_dAmount).collect(Collectors.toList());
return bigDList.stream()
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
Further, I simplified the query. But it still does not care about DB updates, only about fragment recreation:
Single.fromCallable(() -> oStandardModel.getItemsVanilla())
.map(Manager::GetBigSum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(e.toString())
);
Your rx logic has no error. That should be internal error in your getWholeBudget.
But why you write rx so complex?
For your case, you can just write:
Single.fromCallable(() -> oStandardModel.getItemsVanilla())
.map(Manager::GetBigSum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(sum.toString()),
e -> log.error(e));
I solved it this way:
oStandardModel.getItemJointCatLive().observe(this, new Observer<List<ItemJointCat>>() {
#Override
public void onChanged(#Nullable final List<ItemJointCat> oItemSP) {
Single.fromCallable(() -> oStandardModel.getWholeBudget())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(e.toString())
);
}
});
My mistake was that I assumed RXjava2 does not need an onchanged event...now i just use onchanged event of livedata observer to trigger a simple rxjava2 query.
Do you think there is anything wrong with that approach?
Consider the following example, it creates an Observable that wraps another API that produces Widgets
public Observable<Widget> createWidgetObservable() {
return Observable.create(new Observable.OnSubscribe<Widget>() {
#Override
public void call(final Subscriber<? super Widget> subscriber) {
WidgetCreator widgetCreator = new WidgetCreator();
widgetCreator.setWidgetCreatorObserver(new WidgetCreator.WidgetCreatorObserver() {
#Override
public void onWidgetCreated(Widget widget) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(widget);
}
}
#Override
public void onWidgetError(Throwable e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
});
}
});
}
Are the subscriber.isUnsubscribed() checks necessary prior to calling subscriber.onNext() and subscriber.onError()?
If so, are the checks always necessary or does it depend on the composition / subscriber that's using the observable?
Is it best practice to include the checks?
You can use them to narrow the window between an emission and an unsubscription but if you don't have loops, it is unnecessary most of the time. The more important thing is that if an unsubscription happen, you'd have to "unset" the WidgetCreatorObserver otherwise it will keep receiving and dropping data and keeping alive every reference it may hold.
WidgetCreator widgetCreator = new WidgetCreator();
WidgetCreator.WidgetCreatorObserver wo = new WidgetCreator.WidgetCreatorObserver() {
#Override
public void onWidgetCreated(Widget widget) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(widget);
}
}
#Override
public void onWidgetError(Throwable e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
}
widgetCreator.setWidgetCreatorObserver(wo);
wo.add(Subscriptions.create(() -> widgetCreator.removeWidgetCreatorObserver(wo)));
I have this code:
searchButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
statusLabel.setText("Searching...");
final String query = searchField.getText();
RootPanel.get("flickr").clear();
AsyncCallback<Flickr> ac=new AsyncCallback<Flickr>(){
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(Flickr result) {
for(Photo p:result.getPhotos().getPhoto())
{
flck.add(p);
}
statusLabel.setText("");
}
};
mashupService.getFlickrPhotos(query, ac);
if(!flck.isEmpty())
{
for(int i=0;i<flck.size();i++)
{
RootPanel.get("flickr").add(new HTML("<img src='http://farm"+flck.get(i).getFarm()+".staticflickr.com/"+flck.get(i).getServer()+"/"+flck.get(i).getId()+"_"+flck.get(i).getSecret()+".jpg'/><br/>"));
}
}
}
});
I want execute first onSuccess (have flick.add)... but it executes after of if(!flck.isEmpty)... and I need have flck with data but I can't...
When I press secont time the same button, flck have data of first onClick...
Thanks in advance
Move the code inside the onSuccess() method that is depended on the result of AsyncCallback.
It's clear from the name that AsyncCallback is just like a AJAX request that talks to server asynchronously means the execution of code is not sequential.
Just move if(!flck.isEmpty)... inside onSuccess() method.
Just for example, let's check the code below
private void loadUserFromServer() {
dispatchAsync.execute(new FindLoggedUserAction(),
new AsyncCallback<FindLoggerUserResult>() {
#Override
public void onFailure(Throwable caught) {
//do something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
//dosomething with user
result.getUser();
}
operationTwo();
}
My problem is, I have to execute operationTwo(); after some result of dipatcher(Success or failure).
This is just an example, let's assume I can't put operationTwo() inside the onSucess or onFailure()
My real PROBLEM
My GateKeeper of presenters that user must be login.
private UserDTO user;
#Override
public boolean canReveal() {
if(getUser() == null){
ShowMsgEvent.fire(eventBus,"Must Login first", AlertType.ERROR);
return false;
}
return true;
}
}
public UserDTO getUser()
{
if(user == null)
{
//call server
loadUserFromServer();
}
return user;
}
private void loadUsuarioFromServer() {
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
}
});
As you can see, when a Presenter with that Gatekeeper is called and user is null,
getUser() is called, but when dispatch executes, the method doesn't wait until the return of Sucess or Failure
Result: getUser() returns null.
After the sucessful result of dispatch, getUser() returns a DTO. But, as you can see canReveal() already returned false.
Do not think that GateKeeper is a good approach to handle security in your case. You will not be able to reach stable work. Problem that you will have:
You are not handling network connection lost. If you code is already cached but you need to reload User it will be a big problem with double checking.
Sync calls are always problematic, specially with bad network connection. You will have tons of not responding messages.
To handle presenter access it will be better to use revealInParent method. Most of your presenter already overrides it and it looks like:
#Override
protected void revealInParent() {
RevealContentEvent.fire(...);
}
So you can just not fire Reveal event before you actually download user data. In your case the code will looks like:
#Override
protected void revealInParent() {
if(getUser() == null){
RevealContentEvent.fire(...);
return;
}
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
RevealContentEvent.fire(...);
}
});
We have also encountered similar problems. Its better to use Async call chaining. Since you can't do that there are two options for your problem
Setup a timer which will check from time to time whether the user is null or not and return only after when user is populated.
Use JSNI (Native code) and make the synchronous call. But beware this is bad practice
Yes, as Abhijith mentioned in previous answer there are 2 options -
1) Synchronous calls - which GWT doesn't support. So it is ruled out.
2) Setting timer - unless user logs in control will not come out of the timer loop. So failed status will never return from the timer. This approach serves only half of your requierment(serving only success state).
To solve your problem you try the following code snippet -
private UserDTO user;
private CanRevealCallBack revealCallBack;
public interface CanRevealCallBack {
returnStatus(boolean status);
}
#Override
public void canReveal(CanRevealCallBack callBack) {
revealCallBack = callBack;
if(user == null){
loadUserFromServer();
}
else{
revealCallBack.returnStatus( true );
}
}
private void loadUsuarioFromServer() {
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
if(result.getDto() == null){
revealCallBack.returnStatus( true );
}
else{
revealCallBack.returnStatus( false );
}
}
});
So, you have to pass a revealCallback to the canReveal method. CallBack gets executed and returns u the status on success of the async call. In returnStatus method of the callback you can program the logic with the correct user log-in status.
I have the following problem:
I am trying to model a process using GWT, where i have a couple of views with a couple of submit buttons. And pressing button1 will create a server interaction and if everything was ok, the next view will be loaded. My problem is now that I get really nasty spaghetti code (just very highlevel to show you what i mean):
onClick {
AsyncCallback {
onSuccess {
load new view with another clickhandler and an asynccallback
}
}
}
Is there some way to create some kind of abstraction or something? Maybe a state pattern? How? Thanks a lot!
This is actually a very good question - and probably one without a definitive answer. It's a problem that applies to many frameworks, not just GWT, so I like your idea to look at this with some simplified code. I'll make this a little bit longer, to show what even just 4 very simple callbacks look like:
Nested callbacks
alice.call("a", new Callback() {
#Override
public void onSuccess() {
bob.call("b", new Callback() {
#Override
public void onSuccess() {
charlie.call("c", new Callback() {
#Override
public void onSuccess() {
daisy.call("d", new Callback() {
#Override
public void onSuccess() {
// finished
}
});
}
});
}
});
}
});
Named callbacks
You can use your IDE to refactor this easily into named callbacks (hint: Please read the callbacks from bottom to top!):
final Callback daisyCallback = new Callback() {
#Override
public void onSuccess() {
// finished
}
};
final Callback charlieCallback = new Callback() {
#Override
public void onSuccess() {
daisy.call("d", daisyCallback);
}
};
final Callback bobCallback = new Callback() {
#Override
public void onSuccess() {
charlie.call("c", charlieCallback);
}
};
final Callback aliceCallback = new Callback() {
#Override
public void onSuccess() {
bob.call("b", bobCallback);
}
};
alice.call("a", aliceCallback);
Problem: The control flow is not so immediately obvious anymore.
Still, an IDE can help by using "Search References" (Ctrl-G in Eclipse) or something similar.
Event Bus (or Observer/Publish-Subscribe pattern)
This is how the same calls look like with an event bus:
alice.call("a", new Callback() {
#Override
public void onSuccess() {
bus.fireEvent(BusEvent.ALICE_SUCCESSFUL_EVENT);
}
});
bus.addEventListener(BusEvent.ALICE_SUCCESSFUL_EVENT, new BusEventListener() {
#Override
public void onEvent(final BusEvent busEvent) {
bob.call("b", new Callback() {
#Override
public void onSuccess() {
bus.fireEvent(BusEvent.BOB_SUCCESSFUL_EVENT);
}
});
}
});
bus.addEventListener(BusEvent.BOB_SUCCESSFUL_EVENT, new BusEventListener() {
#Override
public void onEvent(final BusEvent busEvent) {
charlie.call("c", new Callback() {
#Override
public void onSuccess() {
bus.fireEvent(BusEvent.CHARLIE_SUCCESSFUL_EVENT);
}
});
}
});
bus.addEventListener(BusEvent.CHARLIE_SUCCESSFUL_EVENT, new BusEventListener() {
#Override
public void onEvent(final BusEvent busEvent) {
daisy.call("d", new Callback() {
#Override
public void onSuccess() {
bus.fireEvent(BusEvent.DAISY_SUCCESSFUL_EVENT);
}
});
}
});
bus.addEventListener(BusEvent.DAISY_SUCCESSFUL_EVENT, new BusEventListener() {
#Override
public void onEvent(final BusEvent busEvent) {
// finished
}
});
Under the right circumstances (when it's very clear what each event means, and
if you don't have too many), this pattern can make things very nice and clear.
But in other cases, it can make the control flow more confusing (and you easily get twice the lines of code).
It's harder to use your IDE to find out about the control flow.
The GWT History mechanism is a very positive example for where to use this technique reasonably.
Divide and Conquer
In my experience, it's often a good idea to "divide and conquer" by mixing nesting and named callbacks:
final Callback charlieCallback = new Callback() {
#Override
public void onSuccess() {
daisy.call("d", new Callback() {
#Override
public void onSuccess() {
// finished
}
});
}
};
alice.call("a", new Callback() {
#Override
public void onSuccess() {
bob.call("b", new Callback() {
#Override
public void onSuccess() {
charlie.call("c", charlieCallback);
}
});
}
});
Depending on the situation, two nested callbacks are often still readable, and they reduce jumping around between methods when reading the code by 50%.
(I created a pastebin of my examples here, if you like to play around with them: http://pastebin.com/yNc9Cqtb)
Spaghetti code is a tricky problem in GWT as it is in Javascript, where much of your code is structured around asynchronous callbacks.
Some of the techniques to deal with it that are described in the answers to this question could apply.
The suggested approach to avoid coupling between widgets is to use EventBus. Read more details here https://developers.google.com/web-toolkit/articles/mvp-architecture#events
Hope it helps.
changeview(boolean first){
if(first)
{
firstView.setVisible(true);
secondView.setVisible(false);
}else{
firstView.setVisible(false);
secondView.setVisible(true);
}
}
onClick {
AsyncCallback {
onSuccess {
changeView(false);
}
}
}
Switch between views by above.
Use MVP from very beginning. Use Activities and Places. Your code will be clean.