Critique my Realm to RxJava 2 Flowable method - java

I'm fairly new to RxJava so I was hoping someone with a bit more knowledge could tear apart my method for getting a Flowable from a RealmResults, maintaining a reference to the resource for the lifetime of the Flowable and then disposing of it at the end. I'd be interested to know any errors I've made. The motivation behind this was to be able to subscribe to live realm queries without exposing Realm to the rest of the app.
One thing I'm not too keen on is that the Realm instance is passed into the function and then the Flowable manages closing it, rather than the caller managing closing it, but I can't see a way of closing the Realm instance in the calling class without either maintaining a seperate reference to it or wrapping the whole thing in another Flowable.using which seems a bit ugly.
public class RxRealm {
private static class ResultsResource<T extends RealmModel> {
final Realm realm;
final RealmResults<T> results;
ResultsResource(Realm realm, RealmResults<T> results) {
this.realm = realm;
this.results = results;
}
}
public static <T extends RealmModel> Flowable<RealmResults<T>> asFlowable(final Realm realm, final RealmResults<T> results) {
return Flowable.using(new Callable<ResultsResource>() {
#Override
public ResultsResource call() throws Exception {
return new ResultsResource<>(realm, results);
}
}, new Function<ResultsResource, Publisher<? extends RealmResults<T>>>() {
#Override
public Publisher<? extends RealmResults<T>> apply(#NonNull ResultsResource resultsResource) throws Exception {
return Flowable.create(new FlowableOnSubscribe<RealmResults<T>>() {
#Override
public void subscribe(#NonNull final FlowableEmitter<RealmResults<T>> emitter) throws Exception {
final RealmChangeListener<RealmResults<T>> changeListener = new RealmChangeListener<RealmResults<T>>() {
#Override
public void onChange(RealmResults<T> element) {
if (!emitter.isCancelled()) {
emitter.onNext(element);
}
}
};
results.addChangeListener(changeListener);
}
}, BackpressureStrategy.LATEST);
}
}, new Consumer<ResultsResource>() {
#Override
public void accept(#NonNull ResultsResource resource) throws Exception {
resource.results.removeAllChangeListeners();
resource.realm.close();
}
});
}
}
Usage:
public Flowable<Integer> getUnreadMessages(final String matchingId) {
Realm realm = Realm.getDefaultInstance();
RealmQuery<Message> query = realm.where(Message.class)
.equalTo("read", false);
if (matchingId != null) {
query.equalTo("id", matchingId);
}
RealmResults<Message> results = query.findAllAsync();
return RxRealm.asFlowable(realm, results)
.map(new Function<RealmResults<Message>, Integer>() {
#Override
public Integer apply(#NonNull RealmResults<Message> realmResults) throws Exception {
return realmResults.size();
}
});
}

Related

How to do retrofti calls with OOP?

Today i was working on my homework, which it was making simple apps with retrofit calls and learning new things for code improvement, and somehow i saw there are so many ways to write less code and do better with OOP. So to improve my code experiment I'm trying to do my retrofit calls with OOP. So this is my issue right now:
Consider a simple retrofit call with CompositeDisposable( I'm developing my simples with MVP ) :
mView.showProgress(1);
RequestRemainingProductsRequest requestRemainingProductsRequest = new RequestRemainingProductsRequest();
requestRemainingProductsRequest.distributorId = distributorId;
requestRemainingProductsRequest.requestCode = requestCode;
requestRemainingProductsRequest.requestType = 1;
NetworkCalls.getObservableList();
compositeDisposable.add(getApi().requestRemainingProducts(requestRemainingProductsRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<Products>>() {
#Override
public void accept(List<Products> products) throws Throwable {
mView.hideProgress(1);
mView.getRemainingProducts(products);
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
mView.hideProgress(1);
mView.showLog(throwable.getMessage().toString());
}
}));
And, Another retrofit call without CompositeDisposable :
ProductSellerRequest productSellerRequest = new ProductSellerRequest();
productSellerRequest.centralId = centralsList.get(i).requestCentralId;
productSellerRequest.requestType = 0;
productSellerRequest.productId = Constant.currentProduct.productId;
getApi().checkProductExistInRequest(productSellerRequest)
.enqueue(new Callback<ProductSellerCallback>() {
#Override
public void onResponse(Call<ProductSellerCallback> call, Response<ProductSellerCallback> response) {
hideProgress(myViewHolder);
showAddDialog(myViewHolder, v, response, i);
}
#Override
public void onFailure(Call<ProductSellerCallback> call, Throwable t) {
hideProgress(myViewHolder);
}
});
So let's say I created a java class with NetworkCalls.java, and created 2 voids like this:
public static void getObservableList()
{
}
public static void getWithoutObservableList()
{
}
How to handle my response to return to my Presenter/Activity?
This is how i using StringBuilder and returning my String, but I'm trying do similiar way to make repository for my Network Calls, then learn all all i should know about Repository Pattern.
public static String TotalPriceStringBuilder(int Price){
String DecimalPrice = String.format("%,d", Price);
String FinalString = new StringBuilder("Price : ").append(DecimalPrice).append(" $").toString();
return String.valueOf(FinalString);
}
This is what I've tried, but i still don't know how to fix it or make it work, what to return, and how to return and etc... :
private static ApiClient mApi;
private List<Products> receivedProducts;
private int hideProgress;
private boolean status;
private String message;
public void getObservableList(RequestRemainingProductsRequest requestRemainingProductsRequest, CompositeDisposable compositeDisposable)
{
compositeDisposable.add(getApi().requestRemainingProducts(requestRemainingProductsRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<Products>>() {
#Override
public void accept(List<Products> products) throws Throwable {
hideProgress = 1;
receivedProducts = products;
status = TRUE;
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
hideProgress = 1;
status = FALSE;
message = throwable.getMessage().toString();
}
}));
if (status == TRUE) {
return hideProgress, receivedProducts, status;
} else {
return hideProgress, message, status;
}
}
public ApiClient getApi() {
if (mApi == null) {
mApi = ApiService.getClient().create(ApiClient.class);
}
return mApi;
}
If i use static method I'll get bunch of errors like can't be refrenced from a static context or etc...

Unit Testing In Network With Using Volley in Android

I am trying to test functions from my Presenter Class. In below, I can reach getSomeThing() function however, I cannot reach the getData() and getError() functions.
Volley functions are not working in unit tests. Further help would be highly appreciated as I am struggling with this for over a week.
Below is my Presenter Class, Presenter Listener and Test Function.
my Presenter Class:
public abstract class SomePresenter implements BasePresenterListener {
private static final String sTAG = SomePresenter.class.getSimpleName();
private Context context;
private Integer testInteger;
protected SomePresenter(Context context, Integer testInteger) {
this.context = context;
this.testInteger = testInteger;
onResponse();
}
#Override
public void onResponse() {
try {
Thread.sleep(1000);
getSomeThing();
} catch (InterruptedException e) {
e.printStackTrace();
}
final GetRequest<SomeResponse> someResponseRequest =
ApiRequests.getSomeResponse(
new Response.Listener<SomeResponse>() {
#Override
public void onResponse(SomeResponse response) {
getData(response);
}
}
,
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(Constant.NETWORK_ERROR);
getError(errorResponse);
}
}
);
NetworkInstance.addRequest(context, poiResponseGetRequest, sTAG);
}
public static void cancelRequest(Context context) {
NetworkInstance.cancelAllRequests(context, sTAG);
}
protected abstract void getSomeThing();
protected abstract void getData(SomeResponse response);
protected abstract void getError(ErrorResponse response);
}
my BasePresenter Class:
public interface BasePresenterListener {
void onResponse();
}
my Unit Test Function:
#Test
public void test() throws InterruptedException {
new SomePresenter(mockContext, 107){
#Override
protected void getData(PoiResponse response) {
SomeLogger.debug("getData works");//this is not called.
}
#Override
protected void getSomeThing() {
SomeLogger.debug("getSomeThing works!");//this is called.
}
#Override
protected void getError(ErrorResponse response) {
SomeLogger.debug("ErrorResponse works!"); //this is not called.
}
};
}
I have looked below links none of them solved my problem.
Unit testing a network response. Works when debugging, not when actually running
Android Unit test with Volley
In my case is I can reach the getSomething() function from unit test but I cannot reach the getData() nor getError() functions because Volley does not seem to work in unit tests.
All, getSomething(), getData(), getError() functions are callback functions, I can reach the getSomeThing() function but I cannot reach the getData() and getError() functions.

Mediation between Hibernate Entity Listeners and netty-socketio

I am working on a small Java project, and here's the basic idea of what I'm trying to achieve: I have a layer over netty-socketio that accepts socket.io requests from the browser, and I use JPA 2.1/hibernate to persist the requested changes to DB. The twist is that I have a concept of stream requests as well, as in a user will request the current state of a collection and all future updates. To get the real-time updates from the DB, I'm using Entity Listeners. I'm looking for a solid way of connecting the entity listener methods to the handler on top of the socketio connection, i.e. the stream handler should be notified when the data it's interested in changed so it can send the update down the pipe. I tried to come up with a singleton moderator of sorts to which the entity listeners could post updates, and subscribed handlers could consume it, all based on a String topic, pretty much like a pubsub. The problem I hit was this: let's take for example the POJO User. When a new user is inserted, the UserEntityListener#PostInsert kicks in, and it forwards the user to the Notifier via a .publish call. The Notifier uses <?> for the data type, and it calls the interested parties via a Callable-like interface:
public interface Notifiable {
public <T> void onEvent(T data);
}
So now the implementation of this is called in the proper handler, but it has the generic type and I have to cast it manually (the handler knows the type it should recieve). My question is, can I do this without explicit casts? Is there a good framework that makes all this low-level tinkering useless? I'd like a centralized solution to bridge the gap, otherwise all the boilerplate's going to kill me.
EDIT Added relevant source.
Notifier class:
class Subscriber {
public String topic;
public Notifiable notifiable;
public Subscriber(String topic, Notifiable n) {
this.topic = topic;
this.notifiable = n;
}
}
public class Notifier {
private static Notifier instance = null;
private List<Subscriber> subscribers = new ArrayList<Subscriber>();
public Notifier() {};
public void subscribe(String topic, Notifiable n) {
if (!this.hasSubscriber(topic, n)) {
this.subscribers.add(new Subscriber(topic, n));
}
}
public <T> void publish(String topic, T data) {
for (Subscriber s : this.subscribers) {
if (s.topic.equals(topic)) {
s.notifiable.onEvent(data);
}
}
}
public Boolean hasSubscriber (String topic, Notifiable n) {
for (Subscriber s : this.subscribers) {
if (s.topic.equals(topic) && s.notifiable == n) {
return true;
}
}
return false;
}
public static Notifier getInstance() {
if (instance == null) {
instance = new Notifier();
}
return instance;
}
}
Entity Listener:
#PostPersist
public void PostInsert(User u) {
Notifier.getInstance().publish("user/new", u);
}
Socketio Handler:
Notifier.getInstance().subscribe("user/new", (new Notifiable() {
#Override
public <T> void onEvent(T data) {
User u = (User) data;
logger.info("User name: " + u.getUsername());
}
}));
If you want to avoid the explicit casting making the following changes:
One, Make your Notifiable interface generic:
public interface Notifiable<T> {
public void onEvent(T data);
}
Two, make Subscriber class also generic:
public class Subscriber<T> {
public String topic;
public Notifiable<T> notifiable;
public Subscriber(String topic, Notifiable<T> n) {
...
}
}
Three, adapt Notifier class
public class Notifier {
private static Notifier instance = null;
#SuppressWarnings("rawtypes")
private List<Subscriber> subscribers = new ArrayList<Subscriber>();
public Notifier() {};
public <T> void subscribe(String topic, Notifiable<T> n) {
if (!this.hasSubscriber(topic, n)) {
this.subscribers.add(new Subscriber<T>(topic, n));
}
}
#SuppressWarnings("unchecked")
public <T> void publish(String topic, T data) {
for (Subscriber<T> s : this.subscribers) {
if (s.topic.equals(topic)) {
s.notifiable.onEvent(data);
}
}
}
#SuppressWarnings("unchecked")
public <T> Boolean hasSubscriber (String topic, Notifiable<T> n) {
for (Subscriber<T> s : this.subscribers) {
/* XXX: Beware, is safe to compare two notifiable
* instances by their memory addresses??
*/
if (s.topic.equals(topic) && s.notifiable == n) {
return true;
}
}
return false;
}
public static Notifier getInstance() {
if (instance == null) {
instance = new Notifier();
}
return instance;
}
}
Four, Socketio Handler:
Notifier.getInstance().subscribe("user/new", (new Notifiable<User>() {
#Override
public void onEvent(User data) {
logger.info("User name: " + u.getUsername());
}
}));

How to properly convert Listeners to Reactive (Observables) using RxJava?

I'm using a multiplayer Game Client that's called AppWarp (http://appwarp.shephertz.com), where you can add event listeners to be called back when event's happen, let's assume we'll be talking about the Connection Listener, where you need to implement this interface:
public interface ConnectionRequestListener {
void onConnectDone(ConnectEvent var1);
void onDisconnectDone(ConnectEvent var1);
void onInitUDPDone(byte var1);
}
My goal here is to mainly create a Reactive version of this client to be used in my Apps Internally instead of using the Client itself directly (I'll also rely on interfaces later instead of just depending on the WarpClient itself as in the example, but that's not the important point, please read my question at the very end).
So what I did is as follows:
1) I introduced a new event, named it RxConnectionEvent (Which mainly groups Connection-Related events) as follows:
public class RxConnectionEvent {
// This is the original connection event from the source client
private final ConnectEvent connectEvent;
// this is to identify if it was Connection / Disconnection
private final int eventType;
public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
this.connectEvent = connectEvent;
this.eventType = eventType;
}
public ConnectEvent getConnectEvent() {
return connectEvent;
}
public int getEventType() {
return eventType;
}
}
2) Created some event types as follows:
public class RxEventType {
// Connection Events
public final static int CONNECTION_CONNECTED = 20;
public final static int CONNECTION_DISCONNECTED = 30;
}
3) Created the following observable which emits my new RxConnectionEvent
import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {
private ConnectionRequestListener connectionListener;
// This is going to be called from my ReactiveWarpClient (Factory) Later.
public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
return Observable.create(new ConnectionObservable(warpClient));
}
private ConnectionObservable(WarpClient warpClient) {
super(warpClient);
}
#Override
public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
subscriber.onStart();
connectionListener = new ConnectionRequestListener() {
#Override
public void onConnectDone(ConnectEvent connectEvent) {
super.onConnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
}
#Override
public void onDisconnectDone(ConnectEvent connectEvent) {
super.onDisconnectDone(connectEvent);
callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
}
// not interested in this method (for now)
#Override
public void onInitUDPDone(byte var1) { }
private void callback(RxConnectionEvent rxConnectionEvent)
{
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(rxConnectionEvent);
} else {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
};
warpClient.addConnectionRequestListener(connectionListener);
subscriber.add(Subscriptions.create(new Action0() {
#Override
public void call() {
onUnsubscribed(warpClient);
}
}));
}
#Override
protected void onUnsubscribed(WarpClient warpClient) {
warpClient.removeConnectionRequestListener(connectionListener);
}
}
4) and finally my BaseObservable looks like the following:
public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
protected WarpClient warpClient;
protected BaseObservable (WarpClient warpClient)
{
this.warpClient = warpClient;
}
#Override
public abstract void call(Subscriber<? super T> subscriber);
protected abstract void onUnsubscribed(WarpClient warpClient);
}
My question is mainly: is my implementation above correct or should I instead create separate observable for each event, but if so, this client has more than 40-50 events do I have to create separate observable for each event?
I also use the code above as follows (used it in a simple "non-final" integration test):
public void testConnectDisconnect() {
connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
.subscribe(new Action1<RxConnectionEvent>() {
#Override
public void call(RxConnectionEvent rxEvent) {
assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
connectionStatus = connectionStatus | 0b0001;
client.disconnect();
} else {
connectionStatus = connectionStatus | 0b0010;
connectionSubscription.unsubscribe();
haltExecution = true;
}
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
fail("Unexpected error: " + throwable.getMessage());
haltExecution = true;
}
});
client.connectWithUserName("test user");
waitForSomeTime();
assertEquals(0b0011, connectionStatus);
assertEquals(true, connectionSubscription.isUnsubscribed());
}
I suggest you avoid extending the BaseObservable directly since it's very error prone. Instead, try using the tools Rx itself gives you to create your observable.
The easiest solution is using a PublishSubject, which is both an Observable and a Subscriber. The listener simply needs to invoke the subject's onNext, and the subject will emit the event. Here's a simplified working example:
public class PublishSubjectWarpperDemo {
public interface ConnectionRequestListener {
void onConnectDone();
void onDisconnectDone();
void onInitUDPDone();
}
public static class RxConnectionEvent {
private int type;
public RxConnectionEvent(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String toString() {
return "Event of Type " + type;
}
}
public static class SimpleCallbackWrapper {
private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();
public ConnectionRequestListener getListener() {
return new ConnectionRequestListener() {
#Override
public void onConnectDone() {
subject.onNext(new RxConnectionEvent(1));
}
#Override
public void onDisconnectDone() {
subject.onNext(new RxConnectionEvent(2));
}
#Override
public void onInitUDPDone() {
subject.onNext(new RxConnectionEvent(3));
}
};
}
public Observable<RxConnectionEvent> getObservable() {
return subject;
}
}
public static void main(String[] args) throws IOException {
SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));
listner.onConnectDone(); // Call the listener a few times, the observable should print the event
listner.onDisconnectDone();
listner.onInitUDPDone();
System.in.read(); // Wait for enter
}
}
A more complex solution would be to use one of the onSubscribe implementations to create an observable using Observable.create(). For example AsyncOnSubscibe. This solution has the benefit of handling backperssure properly, so your event subscriber doesn't become overwhelmed with events. But in your case, that sounds like an unlikely scenario, so the added complexity is probably not worth it.

Chain a series of asynchronous calls

I have a series of asynchronous operations
private void doSomething(){
get("/something", new Callback(){
void onComplete(String data){
updateUi(something, data);
doSomethingElse();
}
});
}
private void doSomethingElse(){
get("/something/else", new Callback(){
void onComplete(String data){
updateUi(somethingElse, data);
doYetAnotherThing();
}
});
}
private void doYetAnotherThing(){
get("/yet/another/thing", new Callback(){
void onComplete(String data){
updateUi(yetAnotherThing, data);
allDone();
}
});
}
This suffers from few problems:
Cannot reuse any of the callbacks elsewhere since each is intrinsically tied to the "next step"
Re-ordering operations or inserting another operation is non-intuitive and involves jumping all over the place.
I have looked at the following options to mitigate this:
ExecuterService#invokeAll - I don't see how this solution can be used without blocking.
RxJava - I would prefer to avoid such a paradigm shift in my application if I can!
Guava's ListenableFutures and its transform method. I saw this referred to in few places around the interwebs nut I honestly don't see how this would solve my problem.
So, the question is: What would be a good pattern to chain a series of asynchronous calls in Java? Looking for a solution that works with Java 7 since I need this for an Android app.
There certainly is some guessing involved, regarding the actual intention and use-case where you encountered this problem. Additionally, it is not entirely clear what something, somethingElse and yetAnotherThing are (where they come from and where they should go).
However, based on the information that you provided, and as an addition to (or rather extension or generalization of) the answer by slartidan: The difference between these dummy calls that you sketched there seem to be
The String argument that is passed to the get method
The Callback that is called
Which method is executed next
You could factor out these parts: The String argument and the Callback could be passed as parameters to a general method that creates a Callable. The sequence of the calls could simply be defined by placing these Callable objects into a list, in the appropriate order, and execute them all with a single threaded executor service.
As you can see in the main method of this example, the sequence of calls can then be configured rather easily:
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChainedAsyncTest {
public static void main(String[] args) throws InterruptedException {
ChainedAsyncTest t = new ChainedAsyncTest();
ExecutorService e = Executors.newFixedThreadPool(1);
e.invokeAll(Arrays.asList(
t.call("/something", t.somethingCallback),
t.call("/something/else", t.somethingElseCallback),
t.call("/yet/another/thing", t.yetAnotherThingCallback),
t.allDone()));
}
private Callback somethingCallback = new Callback() {
#Override
public void onComplete(String data) {
updateUi("something", data);
}
};
private Callback somethingElseCallback = new Callback() {
#Override
public void onComplete(String data) {
updateUi("somethingElse", data);
}
};
private Callback yetAnotherThingCallback = new Callback() {
#Override
public void onComplete(String data) {
updateUi("yetAnotherThing", data);
}
};
private Callable<Void> call(
final String key, final Callback callback) {
return new Callable<Void>() {
#Override
public Void call() {
get(key, callback);
return null;
}
};
}
private Callable<Void> allDone() {
return new Callable<Void>() {
#Override
public Void call() {
System.out.println("allDone");
return null;
}
};
}
interface Callback
{
void onComplete(String data);
}
private void get(String string, Callback callback) {
System.out.println("Get "+string);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.onComplete("result of "+string);
}
private void updateUi(String string, String data) {
System.out.println("UpdateUI of "+string+" with "+data);
}
}
(The example uses invokeAll, which blocks until all tasks have been executed. This could be solved differently to be really non-blocking at the call site. The main idea is to create a list of the tasks, which are all created by the same method call)
Spontainious thought: You could define the chained calls as a method parameter to make your methods reusable. Here is my example code:
public class Scribble {
final Callback step1 = new Callback() {
void onComplete(String string) {
doSomethingElse(step2);
};
};
final Callback step2 = new Callback() {
void onComplete(String string) {
doYetAnotherThing(step3);
};
};
final Callback step3 = new Callback() {
void onComplete(String string) {
allDone();
}
};
private void start() {
doSomething(step1);
}
private void doSomething(final Callback externalCallback) {
get("/something", new Callback() {
void onComplete(String data) {
updateUi(something, data);
externalCallback.onComplete(data);
}
});
}
private void doSomethingElse(final Callback externalCallback) {
get("/something/else", new Callback() {
void onComplete(String data) {
updateUi(somethingElse, data);
externalCallback.onComplete(data);
}
});
}
private void doYetAnotherThing(final Callback externalCallback) {
get("/yet/another/thing", new Callback() {
void onComplete(String data) {
updateUi(yetAnotherThing, data);
externalCallback.onComplete(data);
}
});
}
// - the code below is only to make everything compilable -
public class Callback {
void onComplete(String string) {
}
}
private Object something;
protected Object somethingElse;
protected Object yetAnotherThing;
protected void allDone() {
System.out.println("Scribble.allDone()");
}
protected void updateUi(Object yetAnotherThing2, String data) {
System.out.println("Scribble.updateUi()"+data);
}
private void get(String string, Callback callback) {
System.out.println("get "+string);
callback.onComplete(string);
}
public static void main(String[] args) {
new Scribble().start();
}
}
I totally support the approved answer, but I'm also tossing in something I created for these types of problems that comes in handy when you start adding conditional logic within your chain of asynchronous actions. I recently fermented this into a simple library (jasync-driver).
Here is how you'd wire up your example. As you can see, each task has no knowledge of the task that follows. In contrast to the approved answer, the chaining of the tasks is done through a simple synchronous (...looking) method body instead of a list.
public void doChainedLogic() {
final AsyncTask<Void, Void> doSomething = new AsyncTask<Void, Void>() {
#Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/something", new Callback() {
public void onComplete(String data) {
updateUi(something, data);
resultHandler.reportComplete();
}
});
}
};
final AsyncTask<Void, Void> doSomethingElse = new AsyncTask<Void, Void>() {
#Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/something/else", new Callback() {
public void onComplete(String data) {
updateUi(somethingElse, data);
resultHandler.reportComplete();
}
});
}
};
final AsyncTask<Void, Void> doYetAnotherThing = new AsyncTask<Void, Void>() {
#Override
public void run(Void arg, final ResultHandler<Void> resultHandler) {
get("/yet/another/thing", new Callback() {
public void onComplete(String data) {
updateUi(yetAnotherThing, data);
resultHandler.reportComplete();
}
});
}
};
// This looks synchronous, but behind the scenes JasyncDriver is
// re-executing the body and skipping items already executed.
final JasyncDriver driver = new JasyncDriver();
driver.execute(new DriverBody() {
public void run() {
driver.execute(doSomething);
driver.execute(doSomethingElse);
driver.execute(doYetAnotherThing);
}
});
}
Now here's a tweak to the example that includes some conditional logic that depends upon an asynchronous result:
final AsyncTask<Void, String> checkSomething = new AsyncTask<Void, String>() {
#Override
public void run(Void arg, final ResultHandler<String> resultHandler) {
get("/check/something", new Callback() {
public void onComplete(String data) {
resultHandler.reportComplete(data);
}
});
}
};
final JasyncDriver driver = new JasyncDriver();
driver.execute(new DriverBody() {
public void run() {
driver.execute(doSomething);
if ("foobar".equals(driver.execute(checkSomething))) {
driver.execute(doSomethingElse);
}
driver.execute(doYetAnotherThing);
}
});
As you can see, asynchronous conditional logic is as simple as writing a standard if statement.

Categories

Resources