Last active
December 16, 2020 19:10
-
-
Save wispborne/74eedf55e11d7556a1c5e2d666a1f5ab to your computer and use it in GitHub Desktop.
RxJava wrapper for startActivityForResult and onActivityResult flow. Don't break the chain!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
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
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?