Neither of the two methods here works. Both are prone to a problem when the calling Activity is replaced by the system (for instance, via screen rotation).
In Commonsware's answer, the OnContactPickedListener assigned by requestContact() will refer to a control that no longer exists.
In my own answer, the listener retained by the Activity will vanish, and the new activity's equivalent listener will be null.
However there is a solution, which relies on making the context of the listener reassignable.
Drawing on my previous solution, recast the ActivityResultListener interface as a static class:
abstract public static class ActivityResultListener {
private Context
context_;
public ActivityResultListener( Context context ) {
context_ = context;
}
public Context getContext() { return context_; }
public void setContext( Context context ) { context_ = context; }
abstract public void onResultCode( int resultCode, Intent data );
}
Set up an internal class to record state for the BaseActivity:
protected static class BaseState {
private final ActivityResultListener
activity_result_listener_;
protected BaseState( BaseActivity activity ) {
activity_result_listener_ = activity.activity_result_listener_;
}
protected void setState( BaseActivity activity ) {
activity.activity_result_listener_ = activity_result_listener_;
if (activity.activity_result_listener_ != null) {
activity.activity_result_listener_.setContext( activity );
}
}
}
Note especially the call to setContext() in setState(). This avoids the problems associated with non-static interface implementations, i.e. that their references vanish when the Activity is recreated.
Retain state from within the BaseActivity:
@Override
public Object onRetainNonConfigurationInstance() {
return new BaseState( this );
}
Restore state from within BaseActivity.onCreate()
Object state = getLastNonConfigurationInstance();
if (state instanceof BaseState) {
((BaseState)state).setState( this );
}
In the implementation of ActivityResultListener, be sure to use getContext() and findViewById() to dereference everything on demand rather than storing references:
private static class ContactChoiceListener extends BaseActivity.ActivityResultListener {
private final int
id_;
public ContactChoiceListener( Context context, int id ) {
super( context );
id_ = id;
}
@Override
public void onResultCode( int resultCode, Intent data ) {
if (resultCode == BaseActivity.RESULT_OK) {
AddressEditor editor = (AddressEditor)((BaseActivity)getContext()).findViewById( id_ );
if (editor != null)
editor.add_contact_address( data );
}
}
}
Whew. And the best part is, this is all obsolete because Fragments have a completely different way of dealing with state, using setRetainInstance(boolean).
I will be implementing that version shortly, will post here if there is interest.