Edit: changed Fragment to Partial, I was ignorant of the Fragment object when I wrote this.
I have a partial that contains a button to bring up the contact list. Doing this requires calling
startActivityForResult( new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI), MY_REQUEST_CODE );
and handling the result in my Activity, something like:
public void onActivityResult( int requestCode, int resultCode, Intent data ) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case MY_REQUEST_CODE: {
Address address = contact_address( data );
if (address != null) {
// do something with address
}
} break;
}
}
}
Depending on how I include that partial in my Activity layout, it may be several layers deep in other partials, and there may be more than one instance of the partial.
I would like to avoid propagating the ID of MY_REQUEST_CODE all the way down to the partial that invokes the activity - or any variation thereof, like assigning an onClickListener to the button - I don't want the top level UI to care about how the partial is constructed at all.
Is there a standard way of achieving this? It seems to me that if onActivityResult could be made to accept Uri's instead of int codes, the propagation could have been avoided. I hope I am missing something obvious here...
I didn't feel that Commonsware's solution answered my question, because it required every container of the partial to add handlers for events that are contained wholly within the partial.
I specifically do not want to have to implement handlers for every instance of that partial.
So I came up with a solution of sorts, though I admit it doesn't feel right either.
First, I subclass Activity, and create a small framework for associating a listener with startActivityForResult() and onActivityResult().
public class BaseActivity extends Activity {
// assume that we'll never start more than one activity at a time from our activity (a safe assumption?)
private static final int
LISTENED_REQUEST_CODE = 1000000000;
public static interface ActivityResultListener {
public void onResultCode( int resultCode, Intent data );
}
private ActivityResultListener
activity_result_listener_;
public void startActivityForResult( Intent intent, ActivityResultListener listener ) {
// paranoia
if (activity_result_listener_ != null) {
Log.e( TAG, "Activity trying to start more than one activity at a time..." );
return;
}
activity_result_listener_ = listener;
startActivityForResult( intent, LISTENED_REQUEST_CODE );
}
public void onActivityResult( int requestCode, int resultCode, Intent data ) {
if (requestCode == LISTENED_REQUEST_CODE) {
if (activity_result_listener_ != null) {
ActivityResultListener listener = activity_result_listener_;
activity_result_listener_ = null;
listener.onResultCode( resultCode, data );
return;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
}
Then inside the partial, I call my overloaded startActivityForResult() and implement a listener:
public void onFinishInflate() {
ImageButton contact_button = (ImageButton)findViewById(R.id.contact_button);
contact_button.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View view) {
((BaseActivity)getContext()).startActivityForResult( new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI),
new BaseActivity.ActivityResultListener() {
@Override
public void onResultCode( int resultCode, Intent data ) {
if (resultCode == BaseActivity.RESULT_OK) {
add_contact_address( data );
}
}
});
}
} );
}
So now I can use this partial all over the place without having to define listeners for each instance.
The drawback I see is that subclassing Activity will prevent me from using other Activity types. This could be reworked into an interface/implementation, but then starts to suffer from non-DRY logic once more.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With