How can I know when an object has performed an action? - java

I'd like to create a Service that's capable of creating a number of objects, where each object connects to the internet and downloads some JSON data and a photo. Most of this is pretty straight forward, but I want it to happen one at a time, i.e. a new object cannot be created until the first object has completed its actions.
What's the best way for my Service to know when an object has performed its actions?
Here's a very rough illustration of what I'm looking for:

Use an IntentService. In normal usage, each Intent it receives is processed sequentially and is already in a background thread, so you don't even need to do your network activity in an AsyncTask. Easy.
Alternately, put all your things in a Queue and have the "do next thing" call happen as a result of the onPostExecute() call in AsyncTasks.
Queue<YourObject> unfinished = getQueue();
List<YourObject> finished = new LinkedList<YourObject>();
Handler handler = new Handler(){
handleMessage(Message m){
// Object populated! Start next? Blink lights? Whatever.
}
}
AsyncTask t = new AsyncTask<...>(handler) {
Handler h;
public AsyncTask<...>(Handler h) {
this.h = h;
}
protected V doInBackground(YourObject o) {
// Network stuff, populate the thing
return popualtedThing();
}
protected V onPostExecute(YourObject o) {
h.sendMessage(Message.obtain(0,o);
}
}.execute();

How about this? When the object creation is complete, broadcast an intent (you could use LocalBroadcast for example, if you want it to be private).
In your Service, register for the above mentioned broadcast, and when it is received, perform the next task.

Use listeners. Have the background service register as a listener to the object instance and when the object instance is does it just calls back to all the listeners.

Related

updating UI with a volley request from a different class

I am having trouble with volley (again). I want to run a volley request in a class, so more than one activity can feed off its results and update their UI's accordingly. I have got it return data and call the request from the UI but now im struggling to update the UI with the new data. I have looked at answers but I'm trying to understand the structure and I am at a loss, can some please advise/ talk me through it
assuming I understand what you mean as being:
A Volley request returns, updates some data set through some activity
In this case, assuming the calling activity contains everything, and reminding that this is a very general example, what you should usually do (usually, since there are exceptions to the case), is just insert the data into the data set contained in your UI holder (e.g. your recycler adapter) and update it, an example would be your adapter holding a method similar to this:
public void updateDataSet(List<Item> items)
{
//mItemList is the adapters member list
if (null != mItemList)
{
mItemList.clear();
mItemList.addAll(items);
}
else
mItemList = items;
notifyDataSetChanged();
}
you call this inside the request callback you fired earlier, just make sure to initialize everything BEFORE you fire the request, e.g.
#Override
public void onResponse(JSONObject response)
{
Log.d(TAG + ": ", "somePostRequest Response : " + response.toString());
// here you need to parse to JSON to a list and then call...
List<Item> items = parseResponse(response);
myAdapter.updateDataSet(items);
}
Now, if what you meant was
A Volley request returns in some Activity, I want it to update stuff in another place
there are a couple of options:
As someone said in the comments - you could go for EventBus.
You could hold a DataManager class, which would be a global singleton, in which case you can either hold the data and update it there, and then every activity (in it's onResume or other relevant lifecycle method) knows to pull that data.
You could do the same as option 2, with the exception of that DataManager holding a reference to other UI parts (e.g. Fragments), and triggering member methods in them that pass the data and trigger the updates.
Personally I find option 3 cumbersome and somewhat bad practice, but if all else fails, (and it shouldn't, but if it does) then you can try.
There are more options out there, it depends and varies according to the data, your app architecture, coding style and other stuff you apply.
Hope this helps!
You can use EventBus. To use EventBus you need to register class where you will receive update and when you publish event for those event all classes will receive it.
Here is an example using greenrobot's EventBus :
Event Model :
public class MessageEvent {
/* Additional fields if needed */
}
Subscribe :
EventBus.getDefault().register(this); // In Activity onCreate method
#subscribe
public void onMessageEvent(MessageEvent event){
// this is the method to receive event
}
Publish event :
EventBus.getDefault().post(new MessageEvent());
Now every class subscribed for this event model will be updated.
Note : subscribed classes have to alive, If anyone destroyed they won't receive update.

Does DeferredResult have a race condition when returning a potentially already-set instance?

I'm using DeferredResult in my Spring MVC application to handle some server-side processing of a potentially long-running action. It might be very fast, or it could take a second or two.
But in either case, the incoming HTTP request causes an action to be pushed to a queue, which a separate thread (via an ExecutorService) is responsible for consuming. A callback is then called, notifying the pusher that the operation has completed.
I refactored some of this behavior into a utility method:
public static DeferredResult<String> toResponse(GameManager gameManager, final Player player, Action action) {
DeferredResult<String> deferredResult = new DeferredResult<>();
gameManager.execute(action, new Handler<Result>() {
#Override
public void handle(Result result) {
JSONObject obj;
try {
obj = gameManager.getGameJSON(player);
obj.put("success", result.getResult());
obj.put("message", result.getMessage());
deferredResult.setResult(obj.toString()); // POINT B
} catch (JSONException e) {
deferredResult.setErrorResult(e);
}
}
});
return deferredResult; // POINT A
}
But I'm wondering what happens if the execution of the action happens so quickly that the setResult() method is called (POINT B) on the DeferredResult before it has been returned (POINT A) to the calling method.
Will Spring see the returned DeferredResult already has a value and handle it, or does it only begin "watching" for the setter to be called after the instance has been provided?
I've not used Spring but would say that Class DeferredResult<> would be a pretty poor implementation of a Deferred if settlement timing made any difference to the downstream behaviour.
It seems safe to assume that the behaviour would be identical regardless of asynchronous process' timing - milliseconds, seconds or whatever, with the only proviso that a timeout didn't occur in which case the onTimeout handler would run (if set). Even if the Deferred was settled synchronously, in the same code block that created it, the caller function should act on the outcome as expected.
If this assumption is not valid then the Class DeferredResult<> is not fit for purpose and shouldn't be used.

Unblocking UI Thread while avoiding NetworkOnMainThread Error

I have a function where I have to get code from server and return its operation.
Here is the code
public String getResult
{
// Call to your backend
try {
String url = String.format(Constants.LOGIN_URL,
URLEncoder.encode(countryCode + phoneNumber, "UTF-8"),
URLEncoder.encode(smsCode, "UTF-8"),
URLEncoder.encode(Constants.WHERE_API_KEY, "UTF-8"));
while (new LoginToServer().execute(url).get());
}catch (Exception e)
{}
return result; // Result will be saved to class in onPostExecute()
My LoginToServer returns true if there was an error retrieving the result. Now, This will most obviously remove the Exception of NetworkOnMainThread, however it iwll block UI.
since the function is to be called by some sdks , it is imperative that i make httpconnection so that it completes then pass on the result.
How can I make UI To unblock while executing this code ?
Again i can't call entire function as aysnc because the function is to be called by most sdk functions internally and they will diffidently not call it in Async
You have to use something like an AsyncTask. Of course you can abstract this way from users of your SDK/library so that they call simply call a doLogin() function, and into that function they pass a callback interface that will be called when the login result returns.
public void doLogin(final MyCallback callback) {
new AsyncTask<URL, Void, Boolean> {
protected Boolean doInBackground(URL... urls) {
// make network calls to login in this "background" thread.
loginSuccess = true;
return loginSuccess;
}
protected void onPostExecute(Boolean loginSuccess) {
callback.onResult(loginSuccess);
}
}.execute();
}
Notice how this doLogin method returns immediately, and will call the callback only after the network call has completed (perhaps many seconds later). This is how you do non-blocking work, and keep the main thread and app UI responsive.
How can I make UI To unblock while executing this code ?
Get rid of get() and process the results of the URL in onPostExecute() of your AsyncTask.
Or, replace AsyncTask with a regular thread, and call getResult() on a background thread, with appropriate synchronization logic between them. This would be wasteful, as you should not need two threads here, but it gets the main application thread out of the mix.
You simply cannot call getResult() on the main application thread, for a blocking call, and have that blocking call somehow not block.
Async threads are used for time consuming operations (Network might be slow/server might be slow/ many hops between client server etc.)
To not block the UI thread functioning, while data is being fetched from server, is what async calls are used for.
You can call this function from Asyctasks doInBackground() method.
the UI thread will function normally and process result in PostExecute() callback.
What is the challenge you are facing? surely several functions can call it in async. Do you want to synchronize the Async calls? You can use Executor for that.
Look into Native Android async Class or libraries like LoopJ

How to make a callback from a Service to an Activity

Sorry for bugging you again, but I still can't find a way to make a callback from my activity to a service...
Found a similar question - How to Define Callbacks in Android?
// The callback interface
interface MyCallback {
void callbackCall();
}
// The class that takes the callback
class Worker {
MyCallback callback;
void onEvent() {
callback.callbackCall();
}
}
// Option 1:
class Callback implements MyCallback {
void callback() {
// callback code goes here
}
}
worker.callback = new Callback();
yet not sure how to integrate that sample into my project.
Any suggestions or links to clear tutorials would be great!
That kind of callbacks (Observer pattern) that you are showing in your example won't work between a service and an activity. Use observer patter when, from class A, you created the instance of class B and want to send callbacks from B to A.
With regards to the services and activities, things are completely different. AFAICT, if you want to callback your Activity from a Service, the best method to achieve this is to use ResultReceiver. There are a lot of interesting things about ResultReceiver:
Its constructor receives a Handler (that you must create inside the activity), which will allow you to change UI from the service.
It implements Parcelable thus you can put a reference of your ResultReceiver in the Intent extras that you used to start the service.
Its onReceive method has a result code integer which allows you to generate different kind of callbacks (this is like if your callback interface had many methods). Also, it receives a Bundle which you can use to put all result data.
On the other hand, if you want to do a callback (not sure if that is correct term in this case), from your Activity to your Service, I guess you will have to send a Broadcast message or something like that.

Differentiate events for multiple attached gwt widgets

I've been trying to make multiple Presenters "listen" to the same event but I which to make each event unique to the Presenter.
Ex.
I create 3 Composite widgets each in one different tab. They get all attached to the same event at binding. Let's call it the "NewPrescriptionEvent". If this event is fired, all my 3 composites will try to DO the job. I only want one of them to do it.
The only way I found to do this is by creating a temp event id (an integer inside the event) which I check for each widget which is trying to respond to the event.
Code snippet
private class OnNewPrescription implements NewPrescriptionHandler {
#Override
public void onNewPrescription(NewPrescriptionEvent event, int dataObjectId) {
if (getDataObject().getPatientId() == dataObjectId) {
...
}
}
}
During binding I do the usual:
eventBus.addHandler(NewPrescriptionEvent.TYPE, new OnNewPrescription());
The event:
public class NewPrescriptionEvent extends GwtEvent<NewPrescriptionHandler> {
public static final GwtEvent.Type<NewPrescriptionHandler> TYPE = new GwtEvent.Type<NewPrescriptionHandler>();
private int dataObjectId;
public NewPrescriptionEvent(int dataObjectId) {
this.dataObjectId = dataObjectId;
}
#Override
protected void dispatch(NewPrescriptionHandler handler) {
handler.onNewPrescription(this, dataObjectId);
}
#Override
public GwtEvent.Type<NewPrescriptionHandler> getAssociatedType() {
return TYPE;
}
}
I was thinking that the TYPE need to be different each time but still be the same event. Does anyone have a suggestion?
Thx.
Is it the case that you have an arbitrary number of instances of the same presenter and all are listening to the same event type? And each of your presenters 'controls' a different entity an therefore should only react on events coming from that entity? If that's the case the only solution I see is to parametrize the event as you've done.
Sounds like the EventBus probably isn't the best approach here; this is one of the main problems I've personally had with the EventBus: all events are global, and it's hard to differentiate between different events of a given type.
A good set of rules for asynchronous event handling without a shared EventBus is:
Communicate with child widgets via direct method calls.
Communicate with a parent widget via callbacks/handlers/listeners.
Avoid direct knowledge of sibling widgets (probably beside the point here)
So, the widget that contains the 3 tabs can attach callbacks to each tab that, when called, dispatches each event to its appropriate event handler (Presenters, in your case, I believe).
No global communication required, no knowledge of sources or destinations, only one event type, one reusable tab widget type, and the tab class stays simple. In principle, not too different from adding a ValueChangeHandler to a CheckBox (after all, one doesn't subscribe to check box events via the event bus, you just add a handler directly to the widget).
Rough sketch:
public class TabContainer implements IsWidget {
public TabContainer() {
tab1.addNewPrescriptionHandler(
new NewPrescriptionEventHandler() {
#Override
public void handleNewPrescriptionEvent(NewPrescriptionEvent event) {
handleTab1Event(event);
}
});
tab2.addNewPrescriptionHandler(
new NewPrescriptionEventHandler() {
#Override
public void handleNewPrescriptionEvent(NewPrescriptionEvent event) {
handleTab2Event(event);
}
});
...
}
}
And you might even be able to simplify that with some looping and pairing.
Going the other way, this container can also send events back the other way to your widgets from wherever else using the same principles.
Also, depending on what the Event class contains, you might not even need an Event class; you can define your callbacks and params however you want.
I think the title of the question is your answer.
You need different event types for each of the widgets.
You could try using addHandlerToSource(GwtEvent.Type<H> type, Object source, H handler) if you know the source to listen to.
Another possibility would be to extend EventBus to accept some kind of filter on registration.

Categories