Skip to content
This repository was archived by the owner on Mar 24, 2020. It is now read-only.

Commit 39602be

Browse files
committed
Different approach to onActivityResult dispatch
Previous approach didn't work if the fragment tree was changed between startActivityForResult call and onActivityResult callback.
1 parent 0c8d6c8 commit 39602be

File tree

2 files changed

+153
-82
lines changed

2 files changed

+153
-82
lines changed

src/java/android/support/v4/app/FragmentActivity.java

+5-79
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import android.support.annotation.NonNull;
2929
import android.support.v4.util.SimpleArrayMap;
3030
import android.util.AttributeSet;
31-
import android.util.Log;
3231
import android.view.KeyEvent;
3332
import android.view.Menu;
3433
import android.view.MenuItem;
@@ -39,8 +38,6 @@
3938
import java.io.FileDescriptor;
4039
import java.io.PrintWriter;
4140
import java.util.ArrayList;
42-
import java.util.Iterator;
43-
import java.util.LinkedList;
4441

4542
/**
4643
* Base class for activities that want to use the support-based
@@ -149,19 +146,11 @@ static final class NonConfigurationInstances {
149146
@Override
150147
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
151148
mFragments.noteStateNotSaved();
152-
int treeIndex = requestCode>>16;
153-
if (treeIndex != 0) {
154-
Fragment frag = findFragmentByTreeIndex(treeIndex - 1);
155-
if (frag == null) {
156-
Log.w(TAG, "Activity result no fragment exists for treeIndex: 0x"
157-
+ Integer.toHexString(requestCode));
158-
} else {
159-
frag.onActivityResult(requestCode&0xffff, resultCode, data);
160-
}
161-
return;
149+
if (requestCode>>16 != 0) {
150+
getSupportFragmentManager().onActivityResult(requestCode, resultCode, data);
151+
} else {
152+
super.onActivityResult(requestCode, resultCode, data);
162153
}
163-
164-
super.onActivityResult(requestCode, resultCode, data);
165154
}
166155

167156
/**
@@ -825,72 +814,9 @@ public void startActivityFromFragment(Fragment fragment, Intent intent,
825814
if ((requestCode&0xffff0000) != 0) {
826815
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
827816
}
828-
super.startActivityForResult(intent, (getFragmentTreeIndex(fragment)<<16) + (requestCode&0xffff));
829-
}
830-
831-
private Fragment findFragmentByTreeIndex(int treeIndex) {
832-
BreadthFirstFragmentIterator iterator = new BreadthFirstFragmentIterator(this);
833-
834-
while (iterator.hasNext() && treeIndex > 0) {
835-
iterator.next();
836-
treeIndex--;
837-
}
838-
839-
return iterator.hasNext() ? iterator.next() : null;
817+
super.startActivityForResult(intent, (fragment.getFragmentManager().getActivityRequestCode(fragment)<<16) + (requestCode&0xffff));
840818
}
841819

842-
private int getFragmentTreeIndex(Fragment fragment) {
843-
int index = 0;
844-
845-
BreadthFirstFragmentIterator iterator = new BreadthFirstFragmentIterator(this);
846-
while (iterator.hasNext()) {
847-
index++;
848-
if (iterator.next() == fragment) {
849-
return index;
850-
}
851-
}
852-
853-
throw new IllegalArgumentException("Fragment " + fragment + " not found");
854-
}
855-
856-
private final static class BreadthFirstFragmentIterator implements Iterator<Fragment> {
857-
private final LinkedList<Fragment> mQueue = new LinkedList<Fragment>();
858-
859-
BreadthFirstFragmentIterator(FragmentActivity activity) {
860-
addAll(activity.mFragments);
861-
}
862-
863-
private void addAll(FragmentManagerImpl fragments) {
864-
if (fragments != null) {
865-
ArrayList<Fragment> activeChildFragments = fragments.mActive;
866-
if (activeChildFragments != null) {
867-
for (Fragment fragment : activeChildFragments) {
868-
if (fragment != null) {
869-
mQueue.add(fragment);
870-
}
871-
}
872-
}
873-
}
874-
}
875-
876-
@Override
877-
public boolean hasNext() {
878-
return !mQueue.isEmpty();
879-
}
880-
881-
@Override
882-
public Fragment next() {
883-
Fragment fragment = mQueue.remove();
884-
addAll(fragment.mChildFragmentManager);
885-
return fragment;
886-
}
887-
888-
@Override
889-
public void remove() {
890-
throw new UnsupportedOperationException();
891-
}
892-
}
893-
894820
void invalidateSupportFragment(String who) {
895821
//Log.v(TAG, "invalidateSupportFragment: who=" + who);
896822
if (mAllLoaderManagers != null) {

src/java/android/support/v4/app/FragmentManager.java

+148-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package android.support.v4.app;
1818

1919
import android.content.Context;
20+
import android.content.Intent;
2021
import android.content.res.Configuration;
2122
import android.content.res.TypedArray;
2223
import android.os.Bundle;
@@ -51,6 +52,7 @@
5152
import java.io.PrintWriter;
5253
import java.util.ArrayList;
5354
import java.util.Arrays;
55+
import java.util.HashSet;
5456
import java.util.List;
5557

5658
/**
@@ -357,20 +359,25 @@ public FragmentTransaction openTransaction() {
357359
public static void enableDebugLogging(boolean enabled) {
358360
FragmentManagerImpl.DEBUG = enabled;
359361
}
362+
363+
abstract int getActivityRequestCode(Fragment fragment);
364+
abstract void onActivityResult(int requestCode, int resultCode, Intent data);
360365
}
361366

362367
final class FragmentManagerState implements Parcelable {
363368
FragmentState[] mActive;
364369
int[] mAdded;
365370
BackStackState[] mBackStack;
366-
371+
ActivityRequest[] mPendingActivityRequests;
372+
367373
public FragmentManagerState() {
368374
}
369375

370376
public FragmentManagerState(Parcel in) {
371377
mActive = in.createTypedArray(FragmentState.CREATOR);
372378
mAdded = in.createIntArray();
373379
mBackStack = in.createTypedArray(BackStackState.CREATOR);
380+
mPendingActivityRequests = in.createTypedArray(ActivityRequest.CREATOR);
374381
}
375382

376383
public int describeContents() {
@@ -381,6 +388,7 @@ public void writeToParcel(Parcel dest, int flags) {
381388
dest.writeTypedArray(mActive, flags);
382389
dest.writeIntArray(mAdded);
383390
dest.writeTypedArray(mBackStack, flags);
391+
dest.writeTypedArray(mPendingActivityRequests, flags);
384392
}
385393

386394
public static final Parcelable.Creator<FragmentManagerState> CREATOR
@@ -403,6 +411,47 @@ interface FragmentContainer {
403411
public boolean hasView();
404412
}
405413

414+
final class ActivityRequest implements Parcelable {
415+
final int mFragmentIndex;
416+
final int mRequestIndex;
417+
final int mChildRequestIndex;
418+
419+
ActivityRequest(int fragmentIndex, int requestIndex, int childRequestIndex) {
420+
mFragmentIndex = fragmentIndex;
421+
mRequestIndex = requestIndex;
422+
mChildRequestIndex = childRequestIndex;
423+
}
424+
425+
ActivityRequest(Parcel in) {
426+
mFragmentIndex = in.readInt();
427+
mRequestIndex = in.readInt();
428+
mChildRequestIndex = in.readInt();
429+
}
430+
431+
@Override
432+
public int describeContents() {
433+
return 0;
434+
}
435+
436+
@Override
437+
public void writeToParcel(Parcel dest, int flags) {
438+
dest.writeInt(mFragmentIndex);
439+
dest.writeInt(mRequestIndex);
440+
dest.writeInt(mChildRequestIndex);
441+
}
442+
443+
public static final Parcelable.Creator<ActivityRequest> CREATOR
444+
= new Parcelable.Creator<ActivityRequest>() {
445+
public ActivityRequest createFromParcel(Parcel in) {
446+
return new ActivityRequest(in);
447+
}
448+
449+
public ActivityRequest[] newArray(int size) {
450+
return new ActivityRequest[size];
451+
}
452+
};
453+
}
454+
406455
/**
407456
* Container for fragments associated with an activity.
408457
*/
@@ -426,7 +475,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
426475
ArrayList<Integer> mAvailIndices;
427476
ArrayList<BackStackRecord> mBackStack;
428477
ArrayList<Fragment> mCreatedMenus;
429-
478+
ArrayList<ActivityRequest> mPendingActivityRequests;
479+
ArrayList<Integer> mAvailRequestIndices;
480+
430481
// Must be accessed while locked.
431482
ArrayList<BackStackRecord> mBackStackIndices;
432483
ArrayList<Integer> mAvailBackStackIndices;
@@ -743,6 +794,77 @@ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[]
743794
}
744795
}
745796

797+
@Override
798+
int getActivityRequestCode(Fragment fragment) {
799+
return getActivityRequestIndex(fragment, -1) + 1;
800+
}
801+
802+
private int getActivityRequestIndex(Fragment fragment, int childRequestIndex) {
803+
final ActivityRequest request;
804+
805+
if (mAvailRequestIndices == null || mAvailRequestIndices.isEmpty()) {
806+
if (mPendingActivityRequests == null) {
807+
mPendingActivityRequests = new ArrayList<ActivityRequest>();
808+
}
809+
810+
if (mPendingActivityRequests.size() > 0xffff) {
811+
throw new IllegalStateException("Over 0xffff pending activity requests in " + fragment);
812+
}
813+
814+
request = new ActivityRequest(fragment.mIndex, mPendingActivityRequests.size(), childRequestIndex);
815+
mPendingActivityRequests.add(request);
816+
} else {
817+
request = new ActivityRequest(fragment.mIndex, mAvailRequestIndices.remove(mAvailRequestIndices.size() - 1), childRequestIndex);
818+
mPendingActivityRequests.set(request.mRequestIndex, request);
819+
}
820+
821+
Fragment parent = fragment.getParentFragment();
822+
if (parent != null) {
823+
return parent.mFragmentManager.getActivityRequestIndex(parent, request.mRequestIndex);
824+
} else {
825+
return request.mRequestIndex;
826+
}
827+
}
828+
829+
@Override
830+
void onActivityResult(int requestCode, int resultCode, Intent data) {
831+
if (!dispatchOnActivityResult((requestCode>>16) - 1, requestCode, resultCode, data)) {
832+
Log.w(TAG, "No fragment exists for requestCode: 0x" + Integer.toHexString(requestCode));
833+
}
834+
}
835+
836+
private boolean dispatchOnActivityResult(int requestIndex, int requestCode, int resultCode, Intent data) {
837+
if (!checkElement(mPendingActivityRequests, requestIndex)) {
838+
return false;
839+
}
840+
841+
ActivityRequest resultRequest = mPendingActivityRequests.get(requestIndex);
842+
if (!checkElement(mActive, resultRequest.mFragmentIndex)) {
843+
return false;
844+
}
845+
846+
Fragment fragment = mActive.get(resultRequest.mFragmentIndex);
847+
if (resultRequest.mChildRequestIndex != -1) {
848+
mPendingActivityRequests.set(requestIndex, null);
849+
if (mAvailRequestIndices == null) {
850+
mAvailRequestIndices = new ArrayList<Integer>();
851+
}
852+
mAvailRequestIndices.add(requestIndex);
853+
854+
return fragment.mChildFragmentManager.dispatchOnActivityResult(
855+
resultRequest.mChildRequestIndex,
856+
requestCode, resultCode, data
857+
);
858+
} else {
859+
fragment.onActivityResult(requestCode, resultCode, data);
860+
return true;
861+
}
862+
}
863+
864+
private boolean checkElement(ArrayList<?> list, int index) {
865+
return list != null && index < list.size() && list.get(index) != null;
866+
}
867+
746868
static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
747869
static final Interpolator DECELERATE_CUBIC = new DecelerateInterpolator(1.5f);
748870
static final Interpolator ACCELERATE_QUINT = new AccelerateInterpolator(2.5f);
@@ -1774,11 +1896,18 @@ Parcelable saveAllState() {
17741896
}
17751897
}
17761898
}
1777-
1899+
1900+
// Save pending activity requests
1901+
ActivityRequest[] pendingActivityRequests = null;
1902+
if (mPendingActivityRequests != null) {
1903+
pendingActivityRequests = mPendingActivityRequests.toArray(new ActivityRequest[mPendingActivityRequests.size()]);
1904+
}
1905+
17781906
FragmentManagerState fms = new FragmentManagerState();
17791907
fms.mActive = active;
17801908
fms.mAdded = added;
17811909
fms.mBackStack = backStack;
1910+
fms.mPendingActivityRequests = pendingActivityRequests;
17821911
return fms;
17831912
}
17841913

@@ -1893,6 +2022,22 @@ void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
18932022
} else {
18942023
mBackStack = null;
18952024
}
2025+
2026+
// Restore pending activity requests
2027+
if (fms.mPendingActivityRequests != null) {
2028+
mPendingActivityRequests = new ArrayList<ActivityRequest>();
2029+
if (mAvailRequestIndices != null) {
2030+
mAvailRequestIndices.clear();
2031+
} else {
2032+
mAvailRequestIndices = new ArrayList<Integer>();
2033+
}
2034+
for (int i=0; i<fms.mPendingActivityRequests.length; i++) {
2035+
if (fms.mPendingActivityRequests[i] == null) {
2036+
mAvailRequestIndices.add(i);
2037+
}
2038+
}
2039+
mPendingActivityRequests = new ArrayList<ActivityRequest>(Arrays.asList(fms.mPendingActivityRequests));
2040+
}
18962041
}
18972042

18982043
public void attachActivity(FragmentActivity activity,

0 commit comments

Comments
 (0)