Mortar + Flow with third party libraries hooked to activity lifecycle - android

Some third party libraries use hooks into the activity lifecycle to work correctly - for instance, the Facebook SDK (https://developers.facebook.com/docs/android/login-with-facebook/).
I'm having some trouble figuring out how to reconcile this model cleanly with a single-activity flow+mortar setup.
For instance, if I want to use Facebook login as part of a login Flow (w/ FlowView/FlowOwner), but not otherwise in the activity, what's the smartest way to pull this off if you need hooks for that particular flow in onCreate, onResume, onPause, onDestroy, onSaveInstanceState, onActivityResult, etc?
It's not immediately obvious what the cleanest path is - create an observable for each lifecycle activity stage and subscribe the flow to it? Seems like that path quickly devolves to the same Android lifecycle if you're not careful. Is there a better way?
I love the single activity model, and I'd really like to keep everything managed by flow/mortar and not activities, if possible. Or am I thinking about this in a way that is fundamentally making it more difficult than it should be?

We haven't had a need for start and stop so far, but do have a few spots that rely on pause and resume. We use an ActivityPresenter as you suggest, but avoid any kind of universal superclass. Instead it exposes a service that interested presenters can opt in to. This kind of hookup need is why the onEnterScope(Scope) method was added. Here's the code.
First, have the activity implement this interface:
/**
* Implemented by {#link android.app.Activity} instances whose pause / resume state
* is to be shared. The activity must call {#link PauseAndResumePresenter#activityPaused()}
* and {#link PauseAndResumePresenter#activityResumed()} at the obvious times.
*/
public interface PauseAndResumeActivity {
boolean isRunning();
MortarScope getMortarScope();
}
And have it inject the presenter and make the appropriate calls:
private boolean resumed;
#Inject PauseAndResumePresenter pauseNarcPresenter;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pauseNarcPresenter.takeView(this);
}
#Override public boolean isRunning() {
return resumed;
}
#Override protected void onResume() {
super.onResume();
resumed = true;
pauseNarcPresenter.activityResumed();
}
#Override protected void onPause() {
resumed = false;
super.onPause();
pauseNarcPresenter.activityPaused();
}
#Override protected void onDestroy() {
pauseNarcPresenter.dropView(this);
super.onDestroy();
}
Now interested parties can inject a registrar interface to opt-in to pause and resume calls, without subclassing anything.
/**
* Provides means to listen for {#link android.app.Activity#onPause()} and {#link
* android.app.Activity#onResume()}.
*/
public interface PauseAndResumeRegistrar {
/**
* <p>Registers a {#link PausesAndResumes} client for the duration of the given {#link
* MortarScope}. This method is debounced, redundant calls are safe.
*
* <p>Calls {#link PausesAndResumes#onResume()} immediately if the host {#link
* android.app.Activity} is currently running.
*/
void register(MortarScope scope, PausesAndResumes listener);
/** Returns {#code true} if called between resume and pause. {#code false} otherwise. */
boolean isRunning();
}
Have the client presenter implement this interface:
/**
* <p>Implemented by objects that need to know when the {#link android.app.Activity} pauses
* and resumes. Sign up for service via {#link PauseAndResumeRegistrar#register(PausesAndResumes)}.
*
* <p>Registered objects will also be subscribed to the {#link com.squareup.otto.OttoBus}
* only while the activity is running.
*/
public interface PausesAndResumes {
void onResume();
void onPause();
}
And hook things up like this. (Note that there is no need to unregister.)
private final PauseAndResumeRegistrar pauseAndResumeRegistrar;
#Inject
public Presenter(PauseAndResumeRegistrar pauseAndResumeRegistrar) {
this.pauseAndResumeRegistrar = pauseAndResumeRegistrar;
}
#Override protected void onEnterScope(MortarScope scope) {
pauseAndResumeRegistrar.register(scope, this);
}
#Override public void onResume() {
}
#Override public void onPause() {
}
Here's the presenter that the activity injects to make it all work.
/**
* Presenter to be registered by the {#link PauseAndResumeActivity}.
*/
public class PauseAndResumePresenter extends Presenter<PauseAndResumeActivity>
implements PauseAndResumeRegistrar {
private final Set<Registration> registrations = new HashSet<>();
PauseAndResumePresenter() {
}
#Override protected MortarScope extractScope(PauseAndResumeActivity view) {
return view.getMortarScope();
}
#Override public void onExitScope() {
registrations.clear();
}
#Override public void register(MortarScope scope, PausesAndResumes listener) {
Registration registration = new Registration(listener);
scope.register(registration);
boolean added = registrations.add(registration);
if (added && isRunning()) {
listener.onResume();
}
}
#Override public boolean isRunning() {
return getView() != null && getView().isRunning();
}
public void activityPaused() {
for (Registration registration : registrations) {
registration.registrant.onPause();
}
}
public void activityResumed() {
for (Registration registration : registrations) {
registration.registrant.onResume();
}
}
private class Registration implements Scoped {
final PausesAndResumes registrant;
private Registration(PausesAndResumes registrant) {
this.registrant = registrant;
}
#Override public void onEnterScope(MortarScope scope) {
}
#Override public void onExitScope() {
registrations.remove(this);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Registration that = (Registration) o;
return registrant.equals(that.registrant);
}
#Override
public int hashCode() {
return registrant.hashCode();
}
}
}

So I've been porting a personal app over to flow and mortar to evaluate it for businesses use. I haven't encountered a scenario where I HAD to have the entire activity lifecycle yet, but as things stand with the current version of flow (v0.4) & mortar (v0.7), this is something I think you will have to creatively solve for yourself. I've recognized this as a potential problem for myself and have put some thought of how to overcome it:
I would also like to note that I haven't actually used the Facebook SDK. You will have to choose the best method for yourself.
You could post events from the activity for each Activity life cycle event. You essentially mentioned this approach using RXJava's Observables. If you really really wanted to use RXJava, you could use a PublishSubject for this, but I'd probably go with simple events from an EventBus you could subscribe to. This is probably the easiest approach.
You could also, depending on how the Facebook SDK works, possibly inject the Facebook SDK component in the activity, and from there initialize it. Then also inject the Facebook SDK component into your view to be used. Flow and Mortar's entire system is deeply integrated into dependency injection after all? This approach is also fairly simple, but depending on how the Facebook SDK works it probably isn't the best option. If you did go this route, you'd need to heed my warning at the bottom of this post.
This brings us to my last idea. Square had a similar problem when they needed access to an Activity's ActionBar in it's sub-views/presenters. They exposed access to the ActionBar in their sample app via something they called the ActionBarOwner.java. They then implement the ActionBarOwner interface and give an instance of itself in the DemoActivity.java. If you study how they implemented this and share it through injection, you could create a similar class. AcivityLifecycleOwner or something (the name needs work), and you could subscribe to callbacks on it from a presenter. If you decide to go down this route, and aren't careful you can easily end up with a memory leak. Any time you would subscribe to any of the events (I'd recommend you subscribe in the presenter), you'd need to make sure you unsubscribe in the onDestroy method as well. I've created a short untested sample of what I mean for this solution below.
No matter which approach you use, you'll probably need to make sure your onCreate and onDestroy methods actually come from your presenter, and not the exact events from the activity. If you are only using the sdk on a single view, the activity's onCreate has been called long before your view is instantiated probably, and the onDestroy for the Activity will be called after your view is destroyed. The presenter's onLoad and onDestroy should suffice I think, however I haven't tested this.
Best of luck!
Untested code example for solution #3:
All your presenters could extend this class instead of ViewPresenter and then override each method you wanted events for just like you would in an activity:
public abstract class ActivityLifecycleViewPresenter<V extends View> extends ViewPresenter<V>
implements ActivityLifecycleListener {
#Inject ActivityLifecycleOwner mActivityLifecycleOwner;
#Override protected void onLoad(Bundle savedInstanceState) {
super.onLoad(savedInstanceState);
mActivityLifecycleOwner.register(this);
}
#Override protected void onDestroy() {
super.onDestroy();
mActivityLifecycleOwner.unregister(this);
}
#Override public void onActivityResume() {
}
#Override public void onActivityPause() {
}
#Override public void onActivityStart() {
}
#Override public void onActivityStop() {
}
}
Activity Lifecycle owner that would be injected into the activity and then hooked up to the corresponding events. I purposely didn't include onCreate and onDestroy, as you presenter's wouldn't be able to get access to those events as they wouldn't be created or they would already be destroyed. You'd need to use the presenters onLoad and onDestroy methods in place of those. It's also possible that some of these other events wouldn't be called.
public class ActivityLifecycleOwner implements ActivityLifecycleListener {
private List<ActivityLifecycleListener> mRegisteredListeners
= new ArrayList<ActivityLifecycleListener>();
public void register(ActivityLifecycleListener listener) {
mRegisteredListeners.add(listener);
}
public void unregister(ActivityLifecycleListener listener) {
mRegisteredListeners.remove(listener);
}
#Override public void onActivityResume() {
for (ActivityLifecycleListener c : mRegisteredListeners) {
c.onActivityResume();
}
}
#Override public void onActivityPause() {
for (ActivityLifecycleListener c : mRegisteredListeners) {
c.onActivityPause();
}
}
#Override public void onActivityStart() {
for (ActivityLifecycleListener c : mRegisteredListeners) {
c.onActivityStart();
}
}
#Override public void onActivityStop() {
for (ActivityLifecycleListener c : mRegisteredListeners) {
c.onActivityStop();
}
}
}
Now you need to hook the lifecycle owner to the activity:
public class ActivityLifecycleExample extends MortarActivity {
#Inject ActivityLifecycleOwner mActivityLifecycleOwner;
#Override protected void onResume() {
super.onResume();
mActivityLifecycleOwner.onActivityResume();
}
#Override protected void onPause() {
super.onPause();
mActivityLifecycleOwner.onActivityPause();
}
#Override protected void onStart() {
super.onStart();
mActivityLifecycleOwner.onActivityStart();
}
#Override protected void onStop() {
super.onStart();
mActivityLifecycleOwner.onActivityStop();
}
}

Related

Am I allowed to observe a ViewModel, if I clean up the back references?

The suggested way to implement ViewModel is to expose the changing data by using LiveData objects to activities, fragments and views. There are cases, when LiveData is not an ideal answer or no answer at all.
The natural alternative would be, to apply the observer pattern to the ViewModel, make it an observable. When registering observers to the ViewModel, the ViewModel will hold callback references to notify the observers.
The documentation says, a ViewModel must not hold references to activities, fragments or views. The only answer to the question "why" I found is, that this may cause memory leaks. Then how about cleaning up the references to avoid memory leaks?
For views this is a difficulty. There is no defined moment, when the view goes away. But activities and fragments have a defined lifecycle. So there are places to unregister as observers.
What do you think? Is it valid to register activities as observers to ViewModels if you take care to always unregister them? Did you hit upon any valid information about this question?
I set a small reward for the best answer. It's not because I think it a recommended solution (as it does not work with views). I just want to know and extend my options.
public class ExampleViewModel extends ViewModel {
public interface OnEndListener {
public void onEnd();
}
private List<OnEndListener> onEndListeners = new ArrayList<>();
public void setOnEndListener(OnEndListener onEndListener) {
onEndListeners.add(onEndListener);
}
public void removeOnEndListener(OnEndListener onEndListener) {
onEndListeners.remove(onEndListener);
}
public void somethingHappens() {
for (OnEndListener onEndListener: new ArrayList<OnEndListener>(onEndListeners) ) {
onEndListener.onEnd();
}
}
}
public class ExampleActivity extends AppCompatActivity {
ExampleViewModel exampleViewModel;
ExampleViewModel.OnEndListener onEndListener;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onEndListener = new ExampleViewModel.OnEndListener() {
#Override
public void onEnd() {
finish();
}
};
exampleViewModel = ViewModelProviders.of(this).get(ExampleViewModel.class);
exampleViewModel.setOnEndListener(onEndListener);
}
#Override
protected void onDestroy() {
super.onDestroy();
exampleViewModel.removeOnEndListener(onEndListener);
}
}
To ask "am I allowed..." is not really a useful question, IMO. The docs are clear that what you are suggesting is discouraged and why. That said, I expect that your code would probably work as expected and is therefore "allowed" (i.e. not prevented by a technical constraint).
One possible gotcha scenario: InstanceA of ExampleActivity is started and kicks off some long-running task on the ExampleViewModel. Then, before the task completes, the device is rotated and InstanceA is destroyed because of the configuration change. Then, in between the time when InstanceA is destroyed and a new InstanceB is created, the long-running task completes and your view model calls onEndListener.onEnd(). Except: Oh no! The onEndListener is null because it was cleared when InstanceA was destroyed and hasn't yet been set by InstanceB: NullPointerException
ViewModel was designed (in part) precisely to handle edge cases like the gotcha scenario above. So instead of working against the intended use of the ViewModel, why not just use the tools it offers along with LiveData to accomplish the same thing? (And with less code, I might add.)
public class ExampleActivity extends AppCompatActivity {
ExampleViewModel exampleViewModel;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exampleViewModel = ViewModelProviders.of(this).get(ExampleViewModel.class);
exampleViewModel.getOnEndLive().observe(this, new Observer<Boolean>() {
#Override
public void onChanged(#Nullable Boolean onEnd) {
if (onEnd != null && onEnd) {
finish();
}
}
});
}
}
public class ExampleViewModel extends ViewModel {
private MutableLiveData<Boolean> onEndLive = new MutableLiveData<>();
public MutableLiveData<Boolean> getOnEndLive() {
return onEndLive;
}
public void somethingHappens() {
onEndLive.setValue(true);
}
}
Think of the LiveData in this case not as actual "data" per se, but as a signal that you can pass from your ViewModel to your Activity. I use this pattern all the time.

Android manage multi request rxJava on rotation device

I'm using MVVM on android application and i want to manage requests and rxJava on device rotation, how can i disable request after rotation device and countinue from last request?
this is my simple code to know how can i doing that, but i can't find any document and sample code about it
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_register);
...
Observer<String> myObserver = new Observer<String>() {
#Override
public void onError(Throwable e) {
// Called when the observable encounters an error
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String s) {
// Called each time the observable emits data
Log.e("MY OBSERVER", s);
}
};
Observable.just("Hello").subscribe(myObserver);
}
I'm using latest version of rxJava
Handling rotation is a cool challenge in Android. There're a few ways to do that.
1- Services: You can use a service and handle your network requests or other background operations in service. Also with Services, you'll seperate your business logic from ui.
2- Worker Fragment: Worker fragment is a fragment instance without a layout. You should set your worker fragment's retainInstanceState to true. So you'll save your fragment from orientation change and will not lose your background operations.
Why Worker Fragment? If you set retainInstanceState true to a fragment with layout, you'll leak views.
If you're using MVVM you can implement ViewModel as a Worker Fragment which as setRetainInstanceState = true
3- Global Singleton Data Source: You can create a global singleton data source class which handles your operations in an independent scope from Activity / Fragment lifecycle in your application.
4- Loaders: Loaders can recover state from orientation changes. You handle your operations with loaders but they are designed to load data from disk and are not well suited for long-running network requests.
Extra: You can use Path's Priority Job Queue to persist your jobs:
https://github.com/path/android-priority-jobqueue
Edit: You can check my repo for handling device rotation without using Google's new architecture components. (As an example of Worker Fragment which i pointed in my answer.)
https://github.com/savepopulation/bulk-action
You have the following options:
Use some global Singleton, or your Application class, that holds your logic, not within your Activity's lifecycle
Use a Service that runs next to your activity/application
Use a Loader
Global state is often bad and makes your code hard to test / debug. Services tend to be overkill.
For your use case of device rotation and continuing where one left off you'd usually use a Loader, which keeps running on rotation and only gets destroyed once you leave the activity.
I also recently wrote an article about one possible solution to use Loaders together with RxJava to keep state during orientation changes.
You can take advantage of Fragment#setRetainInstance(true). With that flag set, fragment is not destroyed after device rotation and can be used as an object container. Please look at this sample which also stores Observable - https://github.com/krpiotrek/RetainFragmentSample
you need to override
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
When device is rotated store data in bundle then inside on create check
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null){
//saved instance is null
}else{
//get your stored values here
counter = savedInstanceState.getInt("value",0); //here zero is the default value
}
}
How I'm doing this is to have a singleton class (or any long living Object as explained by savepopulation earlier, but - the trick is to store the loaded data in a BehaviorSubject, and subscribe to that subject in the Activity instead of the original network request.
This way:
public class MyNetworkSingleton {
// This static service survives orientation changes
public static MyNetworkSingleton INSTANCE = new MyNetworkSingleton();
private final BehaviorSubject<String> dataSubject = BehaviorSubject.create();
public Observable<String> getData() {
if (!dataSubject.hasValue()) {
refreshData(); // No data is loaded yet, load initial data from network
}
return dataSubject;
}
public void refreshData() {
someDataSourceCall().subscribe(new Observer<String>() {
#Override
public void onError(Throwable e) {
// Remember, this point also needs error handling of some form,
// e.g. propagating the error to the UI as a Toast
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String data) {
dataSubject.onNext(data); // this refreshes the internally stored data
}
});
}
private Observable<String> someDataSourceCall() {
return // some network request here etc. where you get your data from
}
}
and then:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Observer<String> myObserver = new Observer<String>() {
#Override
public void onError(Throwable e) {
// Called when the observable encounters an error
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String s) {
// Called each time the observable emits data
Log.e("MY OBSERVER", s);
}
};
MyNetworkSingleton.INSTANCE.getData().subscribe(myObserver);
myRefreshButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
// refresh data from network only when button is pressed
MyNetworkSingleton.INSTANCE.refreshData();
}
});
}
This way only first time you need the data from network it will be loaded, or when the user clicks a refresh button (myRefreshButton).

Registering a presenter class to EventBus (android MVP)

I'm using greenrobot's EventBus in my android apps and I absolutely like it.
However, now I'd like to seperate the logic from my fragments by using presenters (MVP).
Is the following possible and is it useful?
Fragment:
public class MyFragment implements IMyFragment {
IMyPresenter mPresenter;
#Override
public View onCreateView(...) {
mPresenter = new MyPresenter(this);
}
#Override
public void onResume() {
// EventBus.getDefault().register(mPresenter); // register presenter to bus
mPresenter.resume();
}
#Override
public void onPause() {
// EventBus.getDefault().unregister(mPresenter); // unregister presenter from bus
mPresenter.pause();
}
#Override
public void doSomething() { // gets called via presenter
// ...
}
}
Presenter:
public class MyPresenter implements IMyPresenter {
IMyFragment mFragment;
// constructor to inject fragment
public MyPresenter(IMyFragment mFragment) {
this.mFragment = mFragment;
}
// handle event
public void onEvent(SomeEvent event) {
mFragment.doSomething();
}
public void resume() {
EventBus.getDefault.register(this);
}
public void pause() {
EventBus.getDefault.unregister(this);
}
}
Does this make sense?
Or is it even dangerous regarding unregistering the presenter from the bus and the complex fragment lifecycle?
Edit: Moved bus registration to presenter itself (Thanks to Nicklas).
Any more comments on this architecture?
You're putting too much responsibility on the View. What you want to do instead is have your Presenter expose a resume() and pause() method, and call those in your View. In those methods you'll register() and unregister() on the EventBus.
This puts all the event-handling code in your Presenter. It also means that you can change the event mechanism you use in your presenter, at any time, without having to change a line of code in your View.
In MVP, the only object you'll want to call non-view-related methods on, from the View, is the associated Presenters.

Writing to a TextView outside of a Fragment

I am using a TextView inside of a Fragment.
I wish to update this TextView outside of the fragment (but also outside of an activity) from a callback class.
For example the user scrolls, the callback is called somewhere in my package, and I want the fragment view to be updated.
Can anybody explain how to do this? I did use a Local Broadcast Receiver but it wasn't fast enough in its updating.
Eventually looked at Otto but as we had Guava I implemented a singleton eventbus and used Guava publish/subscribe model to pass stuff around.
Otto however looks very similar.
Use Otto: http://square.github.io/otto/
public class UpdateEvent {
private String string;
public UpdateListEvent(String string) {
this.string = string;
}
public String getString() {
return string;
}
}
...
...
public void update() {
SingletonBus.INSTANCE.getBus().post(new UpdateListEvent(editText.getText().toString()));
}
...
public class FragmentA extends Fragment {
#Override
public void onResume() {
super.onResume();
SingletonBus.INSTANCE.getBus().register(this);
}
#Override
public void onPause() {
SingletonBus.INSTANCE.getBus().unregister(this);
super.onPause();
}
#Subscribe
public void onUpdateEvent(UpdateEvent e) {
//do something
}
}
public enum SingletonBus {
INSTANCE;
private Bus bus;
private SingletonBus() {
this.bus = new Bus(ThreadEnforcer.ANY);
}
public Bus getBus() {
return bus;
}
}
EventBus is a nice and elegant way for communication between modules in Android apps. In this way you should register your fragment as a event subscriber, and post a this specific event from other part of your code. Keep in mind that only UI thread can work with Views.
I don't exactly understand what you want to achieve and why BroadcastReceiver does not work for you, but you may either:
1) try using callbacks (if it is possible in your app design);
2) try using this or that event bus implementation;
Both would work pretty fast without much overhead, compared to broadcasting.
In case 2 you won't have to maintain callback dependencies/references.

Optional callbacks [duplicate]

This question already has answers here:
Optional Methods in Java Interface
(13 answers)
Closed 8 years ago.
I have the interface
public interface UserResponseCallback {
void starting();
void success();
void error(String message);
void finish();
}
Is it possible to make the methods optional?
A non-abstract class must implement every abstract method it inherited from interfaces or parent classes. But you can use that to allow you to implement only certain required parts as long as you can live with the fact that you can no longer implement the interface at will.
You would create an abstract class that implements the optional part of the interface with empty default implementations like
abstract class UserResponseCallbackAdapter implements UserResponseCallback {
#Override
public void starting() { /* nothing */ }
#Override
public void success() { /* nothing */ }
#Override
public void error(String message) { /* nothing */ }
// finish() intentionally left out
}
You can now create subclasses that have to implement just the required parts while they still can implement the optional parts.
class User {
private final UserResponseCallback callback = new UserResponseCallbackAdapter() {
#Override
public void finish() {
// must be implemented because no empty default in adapter
}
#Override
public void starting() {
// can be implemented
}
};
void foo() {
// can be used like every other UserResponseCallback
CallbackManager.register(callback);
}
}
This technique is for example used by AWT event callbacks e.g. MouseAdapter. It starts getting worth the extra effort once you use the callback multiple times since the optional part needs to be implemented only once instead of every time.
Your next option is top split the interface into two. Your conceptional problem is that your interface contains more than it should have, compare Interface Segregation Principle. You could split it either into two or more actually independent interfaces or you could extend a required base interface with optional extra features like
interface UserResponseCallbackBase {
// this is the only required part
void finish();
}
interface UserResponseCallbackFull extends UserResponseCallbackBase {
void starting();
void success();
void error(String message);
void finish();
}
To use that kind of hierarchical callback you would probably add some intelligence to whatever class manages the callbacks and let it check whether or not a callback wants a certain callback based on it's type.
For example like
class CallbackManager {
private List<UserResponseCallbackBase> mCallbacks = new ArrayList<UserResponseCallbackBase>();
public void register(UserResponseCallbackBase callback) {
mCallbacks.add(callback);
}
public void notifyStarting() {
for (UserResponseCallbackBase callback : mCallbacks) {
// check if callback is of the extended type
if (callback instanceof UserResponseCallbackFull) {
((UserResponseCallbackFull)callback).starting();
} // else, client not interested in that type of callback
}
}
}
That way you can freely choose which type of interface you want to implement and the calling code checks whether or not you want to get a callback. I.e. if you register(new UserResponseCallbackFull() {...}) you would be notified about starting(), if you were to register(new UserResponseCallbackBase() {...}) you would not.
This technique is used in Android with ComponentCallbacks2 which you register via Context#registerComponentCallbacks(ComponentCallbacks) - it takes both a "simple" ComponentCallbacks and the extended version and checks what type you gave it.
No, that's not possible in Java.
Have a look at this question that comes to the same conclusion: Optional Methods in Java Interface
No.
Use a dummy implementation and override if needed.

Categories

Resources