Java Question New thread or PendingResult

barx

Well-Known Member
Licensed User
Longtime User
Is there any difference between the following 2 methods

Pending Result
B4X:
            PendingResult<MessageApi.SendMessageResult> results = Wearable.MessageApi.sendMessage(mGoogleApiClient, NodeID, msgPath, Data.getBytes());
            results.setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {

                @Override
                public void onResult(SendMessageResult msgResult) {
                    if (mBA.subExists(mEventname + "_messagesent")) {
                        boolean Success = false;
                        if (msgResult.getStatus().isSuccess()) {
                            Success = true;
                        }
                        mBA.raiseEvent(mGoogleApiClient, mEventname + "_messagesent", new Object[] {Success});
                    }  
                }
              
            });
VS
New Thread
B4X:
            new Thread(new Runnable() {
                @Override
                public void run() {
                    BA.Log("Sending message to " + NodeID);
                    mGoogleApiClient.blockingConnect(Timeout, TimeUnit.MILLISECONDS);
                    SendMessageResult result = Wearable.MessageApi.sendMessage(mGoogleApiClient, NodeID, msgPath, Data.getBytes()).await();
                    boolean success = false;
                    if (result.getStatus().isSuccess()) {
                        success = true;
                    }
                    if (mBA.subExists(mEventname + "_messagesent")) {
                        mBA.raiseEvent(mGoogleApiClient, mEventname + "_messagesent", new Object[] {success});
                    }
                }
            }).start();
        }

From what I have read, both run the code 'not in the main UI thread'.
 

thedesolatesoul

Expert
Licensed User
Longtime User
From what I have read, both run the code 'not in the main UI thread'.
When you word it like that its hard to answer. Some code is run in the main thread and some isnt.

The first example, as long as you launch it in the main thread, all the code that you have posted will run in the main thread. The sendMessage itself will however not wait for the result, so it probably has a handler or listener somewhere that listens in another thread, but when it raises back your onResult event is will be back in the main thread.

The second one is doing everything in the new thread, therefore you cant use raiseEvent in that one.
 

barx

Well-Known Member
Licensed User
Longtime User
The thing i'm not liking about using GoogleApiClient is most things seem to utilize PendingResults. The options with these are you create a callback as first example above or you .await() which blocks the thread. So if you remove the 'new Thread' it will run in the main thread, but block it which is a big no no. I don't think either way will give me the standard practice of

B4X:
var = method.action()

the above examples don't really require it but methods such as .GetDataMap also depend on pendingResults. The end result is going to be a lot of callbacks (events).

Example:

B4X:
DataLayer1.GetDataMap("path")

...
...
Sub DataLayer1_GotDataMap(Result as DataMap)

Anybody see anything I missing?
Anybody even know what I'm on about? I don't know if I'm making sense......
 

thedesolatesoul

Expert
Licensed User
Longtime User
They crammed so much into GoogleApiClient that everything is a bunch of events. However in Java its not so bad as the event is declared right there with the object so it makes more sense.
It is certainly a pain, I am surprised but I guess they are using the same structure to sync on both sides (Wearable and device), so it makes sense to wait until they are both ready?

If you have followed Google APIs you would have known better than to port ver0 of any API. Remember how many revisions there were to Notifications API? Chromecast API is also undergoing changes, Drive/Documents API, Google Play Services...the list goes on.
 

Informatix

Expert
Licensed User
Longtime User
The thing i'm not liking about using GoogleApiClient is most things seem to utilize PendingResults.
For me, these PendingResult are a big improvement over the previous event system. Now you can specify a time out, you can call the function in a background thread and wait for the result (with no event involved), or cancel the function. The negative point is that you have to write more code in your wrapper.

I draw your attention on a very important point mentioned in the Troubleshooting section of the Google Play Services documentation: DON'T USE anonymous listeners (e.g. setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {...) because they are treated as weak references by the library. So, if your app needs some memory, these references will be wiped out and your functions will have no result. You have to create a class that implements the listener and create a persistent instance of this class. Here's an example of what I do in my new GooglePlayServices lib:
B4X:
    private class InitiateMatchEvent implements ResultCallback<InitiateMatchResult>
    {
        private BA _ba;
        private String _evtName;

        public InitiateMatchEvent(BA ba, String evtName)
        {
            _ba = ba;
            _evtName = evtName;
        }

        @Override
        public void onResult(InitiateMatchResult Result)
        {
            RaiseEvent(_ba, _evtName, Result, "InitiateMatchResult");
        }
    }

...
            ResultCallback<InitiateMatchResult> RC_Initiate = new InitiateMatchEvent(ba, EventName);
            if (Time < 0)
                ((PendingResult<InitiateMatchResult>)_PR).setResultCallback(RC_Initiate);
            else
                ((PendingResult<InitiateMatchResult>)_PR).setResultCallback(RC_Initiate, Time, TimeUnit.MILLISECONDS);
...
 
Last edited:

barx

Well-Known Member
Licensed User
Longtime User
You make a valid point @Informatix, but what happens when you have more than one method that has an onResult? More to the point, more than one onResult that passes the same parameter type (so no overloading (if that would even work here)).

Cheers
 

Informatix

Expert
Licensed User
Longtime User
You make a valid point @Informatix, but what happens when you have more than one method that has an onResult? More to the point, more than one onResult that passes the same parameter type (so no overloading (if that would even work here)).

Cheers
I don't understand what you mean. Having one or many functions with a pending result is the same thing. The code that I posted above is generic. It is called by different functions, e.g.:
B4X:
    public PendingResultWrapper FinishMatch(String MatchId)
    {
        PendingResult<UpdateMatchResult> PR = _TBMP.finishMatch(GooglePlayConnection.getAPIclient(), MatchId);
        return new PendingResultWrapper(PR, UpdateMatchResult.class);
    }
...
    public PendingResultWrapper TakeTurn(String MatchId, byte[] MatchData, String PendingParticipantId)
    {
        PendingResult<UpdateMatchResult> PR;
        if (PendingParticipantId.length() == 0)
            PR = _TBMP.takeTurn(GooglePlayConnection.getAPIclient(), MatchId, MatchData, null);
        else
            PR = _TBMP.takeTurn(GooglePlayConnection.getAPIclient(), MatchId, MatchData, PendingParticipantId);
        return new PendingResultWrapper(PR, UpdateMatchResult.class);
    }
In B4A, the user can specify the event of his choice for each function, so it can group events or have a different event for each function:
B4X:
    Dim PR As GPlayPendingResult = TBMulti.CreateMatch(Config)
    PR.SetResultEvent(EventName)
It's an improvement over the previous system which had listeners common to many functions.

You have to write more code because you have to create a named class to wrap each result class (InitiateMatchResult, UpdateMatchResult, CancelMatchResult, etc.) but once you created one, the others are just copied/pasted and there's not a lot of different result classes.
 

barx

Well-Known Member
Licensed User
Longtime User
They crammed so much into GoogleApiClient that everything is a bunch of events. However in Java its not so bad as the event is declared right there with the object so it makes more sense.
It is certainly a pain, I am surprised but I guess they are using the same structure to sync on both sides (Wearable and device), so it makes sense to wait until they are both ready?

If you have followed Google APIs you would have known better than to port ver0 of any API. Remember how many revisions there were to Notifications API? Chromecast API is also undergoing changes, Drive/Documents API, Google Play Services...the list goes on.

I understand what your saying about ver0 and frequent changes, but if we don't get involved now, we miss out on the action.
 

barx

Well-Known Member
Licensed User
Longtime User
I don't understand what you mean. Having one or many functions with a pending result is the same thing. The code that I posted above is generic. It is called by different functions, e.g.:
B4X:
    public PendingResultWrapper FinishMatch(String MatchId)
    {
        PendingResult<UpdateMatchResult> PR = _TBMP.finishMatch(GooglePlayConnection.getAPIclient(), MatchId);
        return new PendingResultWrapper(PR, UpdateMatchResult.class);
    }
...
    public PendingResultWrapper TakeTurn(String MatchId, byte[] MatchData, String PendingParticipantId)
    {
        PendingResult<UpdateMatchResult> PR;
        if (PendingParticipantId.length() == 0)
            PR = _TBMP.takeTurn(GooglePlayConnection.getAPIclient(), MatchId, MatchData, null);
        else
            PR = _TBMP.takeTurn(GooglePlayConnection.getAPIclient(), MatchId, MatchData, PendingParticipantId);
        return new PendingResultWrapper(PR, UpdateMatchResult.class);
    }
In B4A, the user can specify the event of his choice for each function, so it can group events or have a different event for each function:
B4X:
    Dim PR As GPlayPendingResult = TBMulti.CreateMatch(Config)
    PR.SetResultEvent(EventName)
It's an improvement over the previous system which had listeners common to many functions.

You have to write more code because you have to create a named class to wrap each result class (InitiateMatchResult, UpdateMatchResult, CancelMatchResult, etc.) but once you created one, the others are just copied/pasted and there's not a lot of different result classes.


Thanks again @Informatix, what your doing above doesn't make 100% sense to me just yet but I'm sure it will if I stare at it long enough. Your skill and understanding on these things are a few levels above mine :confused:
 
Top