Skip to content

Instantly share code, notes, and snippets.

@wispborne
Last active December 16, 2020 19:10
Show Gist options
  • Save wispborne/74eedf55e11d7556a1c5e2d666a1f5ab to your computer and use it in GitHub Desktop.
Save wispborne/74eedf55e11d7556a1c5e2d666a1f5ab to your computer and use it in GitHub Desktop.
RxJava wrapper for startActivityForResult and onActivityResult flow. Don't break the chain!
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import com.mywebgrocer.util.ActivityResultData;
import java.util.Random;
import rx.Single;
import rx.subjects.PublishSubject;
/**
* Wraps an activity that is launched for a result (`startActivityForResult`), exposing it as an observable.
* THIS CLASS IS NOT THREAD-SAFE.
*
* @author David Whitman on Apr 28, 2017.
*/
public class ObservableActivityForResult extends AppCompatActivity {
private static int REQUEST_CODE = -1;
private static final String EXTRA_INTENT_TO_LAUNCH = "EXTRA_INTENT_TO_LAUNCH";
private static PublishSubject<ActivityResultData> resultSubject;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivityForResult(getIntent().getParcelableExtra(EXTRA_INTENT_TO_LAUNCH), REQUEST_CODE);
}
/**
* Convenience method to create an instance of this class and launch the activity.
* Emits a result based on the result of the activity, then finishes.
* Should never call `onError`.
* Do not call this method in parallel, it will make bad things happen.
*/
public static Single<ActivityResultData> startActivityForResult(@NonNull Context context, @NonNull Intent intentToLaunch) {
// Use Single.create so that resultSubject isn't assigned until the Single is subscribed to.
// Otherwise, this would not work properly if the user wanted to chain two calls
// because the resultSubject wouldn't get reinstantiated when the second Single was subscribed to.
return Single.create(s -> {
// Use random int for each call so a previous result can't somehow intrude on a subsequent one
REQUEST_CODE = new Random().nextInt(32767); // Can only use lower 16 bits for request code
resultSubject = PublishSubject.create();
final Intent intent = new Intent(context, ObservableActivityForResult.class);
intent.putExtra(EXTRA_INTENT_TO_LAUNCH, intentToLaunch);
context.startActivity(intent);
resultSubject.toSingle().subscribe(s);
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
resultSubject.onNext(new ActivityResultData(requestCode, resultCode, data));
resultSubject.onCompleted();
finish();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!resultSubject.hasCompleted()) {
resultSubject.onCompleted();
}
resultSubject = null;
}
}
@FlorianMarsch
Copy link

Hi, i just saw this and i think its a realy nice piece of code. Do you have any experience with when the started activity crashes? can the single be repeated as expected?

@wispborne
Copy link
Author

Thanks, not sure though; I moved on to Kotlin Coroutines a couple years ago and haven't thought about RxJava since.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment