android
registerForActivityResult 메서드의 동작과정
android by kotlin
2022. 2. 3. 20:09
//1. ActivityResultRegistry를 구현한 객체를 생성한다. 개발자가 ActivityResultLauncher.launch() 메서드를 호출할 때 사용될 onLaunch 메서드를 재정의해두었다.
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
ActivityResultCaller {
//...
private final ActivityResultRegistry mActivityResultRegistry = new ActivityResultRegistry() {
@Override
public <I, O> void onLaunch(
final int requestCode,
@NonNull ActivityResultContract<I, O> contract,
I input,
@Nullable ActivityOptionsCompat options) {
...
else {
// startActivityForResult path
ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
}
}
}
//2. 콜백객체와 Contract 를 HashMap 에 저장하는 메서드를 호출한다.
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultRegistry registry,
@NonNull final ActivityResultCallback<O> callback) {
return registry.register(
"activity_rq#" + mNextLocalRequestCode.getAndIncrement(), this, contract, callback);
}
//4. 생명주기를 확인해 STARTED 이면 예외를 발생시키고 종료되며
// STARTED 이전이면 LifecycleEventObserver를 등록해 onStart 생명주기가 되었을 때 Contract와 콜백객체를 HashMap에 저장하며
// ActivityResultLauncher 객체를 생성하여 반환해준다.
@NonNull
public final <I, O> ActivityResultLauncher<I> register(
@NonNull final String key,
@NonNull final LifecycleOwner lifecycleOwner,
@NonNull final ActivityResultContract<I, O> contract,
@NonNull final ActivityResultCallback<O> callback) {
Lifecycle lifecycle = lifecycleOwner.getLifecycle();
//생명주기가 STARTED 이후라면 예외를 발생시킨다.(registerForActivityResult 메서드는 onStart 이전 단계에서 호출되지 않으면 예외가 발생한다.)
if (lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
throw new IllegalStateException("LifecycleOwner " + lifecycleOwner + " is "
+ "attempting to register while current state is "
+ lifecycle.getCurrentState() + ". LifecycleOwners must call register before "
+ "they are STARTED.");
}
//...
LifecycleEventObserver observer = new LifecycleEventObserver() {
@Override
public void onStateChanged(
@NonNull LifecycleOwner lifecycleOwner,
@NonNull Lifecycle.Event event) {
if (Lifecycle.Event.ON_START.equals(event)) {
//생명주기가 onStart 가 되었을 때 mKeyToCallback HashMap 에 콜백객체와 Contract 를 넣는다.
mKeyToCallback.put(key, new ActivityResultRegistry.CallbackAndContract<>(callback, contract));
if (mParsedPendingResults.containsKey(key)) {
@SuppressWarnings("unchecked") final O parsedPendingResult = (O) mParsedPendingResults.get(key);
mParsedPendingResults.remove(key);
callback.onActivityResult(parsedPendingResult);
}
final ActivityResult pendingResult = mPendingResults.getParcelable(key);
if (pendingResult != null) {
mPendingResults.remove(key);
callback.onActivityResult(contract.parseResult(
pendingResult.getResultCode(),
pendingResult.getData()));
}
}
//...
}
};
//ActivityResultLauncher 객체를 반환해준다. 이 객체의 launch 메서드를 호출하여 Intent 를 실행시킬 수 있다.
return new ActivityResultLauncher<I>() {
@Override
public void launch(I input, @Nullable ActivityOptionsCompat options) {
mLaunchedKeys.add(key);
Integer innerCode = mKeyToRc.get(key);
onLaunch((innerCode != null) ? innerCode : requestCode, contract, input, options);
}
@Override
public void unregister() {
ActivityResultRegistry.this.unregister(key);
}
@NonNull
@Override
public ActivityResultContract<I, ?> getContract() {
return contract;
}
};
}
//5. 반환받은 ActivityResultLauncher 의 launch 메서드를 호출해 Intent 를 시작한다.
// 이때 1번에서 overriding 한 onLaunch 메서드가 실행되며 onLaunch 메서드 내에서 startActivityResult 메서드를 호출하여 액티비티 전환이 발생한다.
private fun signIn() {
val signInIntent = googleSignInClient.signInIntent
activityForResult.launch(signInIntent)
}
//6. 이전 액티비티로 반환되었을 때 호출된다.
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
//7. 저장해두었던 콜백객체와 Contract 를 가져와서 콜백객체의 onActivityResult(registerForActivityResult 메서드를 호출할 때 전달한 람다식)이 호출된다.
private <O> void doDispatch(String key, int resultCode, @Nullable Intent data,
@Nullable ActivityResultRegistry.CallbackAndContract<O> callbackAndContract) {
if (callbackAndContract != null && callbackAndContract.mCallback != null) {
ActivityResultCallback<O> callback = callbackAndContract.mCallback;
ActivityResultContract<?, O> contract = callbackAndContract.mContract;
callback.onActivityResult(contract.parseResult(resultCode, data));
} else {
// Remove any parsed pending result
mParsedPendingResults.remove(key);
// And add these pending results in their place
mPendingResults.putParcelable(key, new ActivityResult(resultCode, data));
}
}