EventCallback
EventCallback
allows creating instances of Retrofit callbacks using short, fluent syntax. Wrapper for use with Otto bus is also provided.
Instead of creating classes manually (where you have to take care not to leak anything)
new Callback<SuccessDTO>() {
@Override
public void success(SuccessDTO s, Response response) {
boolean stillSameSession = myCodeCheckingIfItIsStillSameSession();
if(stillSameSession) {
bus.post(new MyEvent());
bus.post(new SuccessEvent());
}
}
@Override
public void failure(RetrofitError error) {
RestErrorWithMsg restErrorWithMsg = myCodeThatTriesToConvertRetrofitErrorToReasonCallFailed(error);
bus.post(new LoginValidationFailedEvent(restErrorWithMsg));
}
};
you can use EventCallback
like this:
MyEventCallback.<SuccessDTO>builder()
.onSuccess().postResponseEvents(new MyEvent(), new SuccessEvent()).validThisSessionOnly()
.onError().postEvents(new LoginValidationFailedEvent()).validBetweenSessions()
.build();
How to use
Including dependency
Add to your build.gradle
:
compile 'com.byoutline.ottoeventcallback:ottoeventcallback:1.3.2' // If you want to use it with Otto
compile 'com.byoutline.eventcallback:eventcallback:1.3.2' // If you want to use it without otto, or force different eventcallback version
Init common settings
In many cases you may want to use same config and error message for single endpoint. To specify your generic error class you must extend EventCallbackBuilder
:
import com.byoutline.eventcallback.CallbackConfig;
import com.byoutline.eventcallback.EventCallbackBuilder;
import com.google.gson.reflect.TypeToken;
public class MyEventCallback<S> extends EventCallbackBuilder<S, RestErrorWithMsg> {
public static CallbackConfig config;
private MyEventCallback() {
super(MyEventCallback.config, new TypeToken<RestErrorWithMsg>() {});
}
public static <S> MyEventCallback<S> builder() {
return new MyEventCallback<>();
}
}
and init its default CallbackConfig
in your Application
onCreate
method:
MyEventCallback.config = new CallbackConfig(BuildConfig.DEBUG, bus, sessionIdProvider);
Usually dependency injection is used to create bus instance and sessionIdProvider
and inject them into Application
:
public class App extends Application {
public static final String App.INJECT_NAME_SESSION_ID = "INJECT_NAME_SESSION_ID";
@Inject
IBus bus;
@Inject
@Named(App.INJECT_NAME_SESSION_ID)
Provider<String> sessionIdProvider;
// onCreate
}
in module file (Dagger/Dagger 2 example):
@Provides
@Singleton
public IBus provideBus() {
return new PostFromAnyThreadBus();
}
@Provides
@Named(App.INJECT_NAME_SESSION_ID)
public String providesSessionId(LoginManager loginManager) {
return loginManager.getUserIdSha();
}
Create callback where you need them
MyEventCallback.<UserResponse>builder()
.onSuccess().postResponseEvents(new MyEvent()).validBetweenSessions()
.onError().postEvents(new LoginValidationFailedEvent()).validBetweenSessions()
.build();
Available bus wrappers
Depending on your application different Bus wrappers may be most suitable. If you use default Bus
instance use OttoBus
or PostFromAnyThreadBus
. If you initiated bus elsewhare or you have your custom Bus
implementation ..IBus
classes may be better chocie.
If you use events mainly to update UI state PostFromAnyThread...
classes will be more convenient.
Class name | requires passing bus instance | ensures that event is posted on android main thread |
---|---|---|
OttoBus | No | No |
OttoIBus | Yes | No |
PostFromAnyThreadBus | No | Yes |
PostFromAnyThreadIBus | Yes | Yes |
By default Otto uses ThreadEnforcer.MAIN which will crash if you try to post event from different thread. You can use PostFromAnyThreadBus
and PostFromAnyThreadIBus
without including rest of event callback by adding dependency:
compile 'com.byoutline.ottoeventcallback:anythreadbus:1.0.0'
validThisSessionOnly vs validBetweenSessions
validThisSessionOnly
can prevent situation when event arrives when it is no longer needed/desired. For example if fetching some user data takes very long time and in the meantime he switches accounts, EventCallback
can detect that and discard event. To do that you must setup session id provider
in a way where it returns different values for different users. validBetweenSessions
always delivers events and ignores session id
value