Skip to content

Commit 71359c7

Browse files
daniel-googleglide-copybara-robot
authored andcommittedJul 19, 2019
Support Fragments which are not hosted by Activities.
A Fragment host can be of any type; if it is not an Activity, then calling #getActivity will always return null. Use #getContext instead, which works similarly but is non-null while the Fragment is attached. PiperOrigin-RevId: 259059132
1 parent 31b501d commit 71359c7

File tree

4 files changed

+89
-16
lines changed

4 files changed

+89
-16
lines changed
 

‎library/src/main/java/com/bumptech/glide/Glide.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ public static RequestManager with(@NonNull FragmentActivity activity) {
769769
*/
770770
@NonNull
771771
public static RequestManager with(@NonNull Fragment fragment) {
772-
return getRetriever(fragment.getActivity()).get(fragment);
772+
return getRetriever(fragment.getContext()).get(fragment);
773773
}
774774

775775
/**

‎library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,13 @@ public RequestManager get(@NonNull FragmentActivity activity) {
134134
@NonNull
135135
public RequestManager get(@NonNull Fragment fragment) {
136136
Preconditions.checkNotNull(
137-
fragment.getActivity(),
137+
fragment.getContext(),
138138
"You cannot start a load on a fragment before it is attached or after it is destroyed");
139139
if (Util.isOnBackgroundThread()) {
140-
return get(fragment.getActivity().getApplicationContext());
140+
return get(fragment.getContext().getApplicationContext());
141141
} else {
142142
FragmentManager fm = fragment.getChildFragmentManager();
143-
return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
143+
return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
144144
}
145145
}
146146

@@ -301,7 +301,7 @@ private void findAllFragmentsWithViewsPreO(
301301
}
302302

303303
@Nullable
304-
private Activity findActivity(@NonNull Context context) {
304+
private static Activity findActivity(@NonNull Context context) {
305305
if (context instanceof Activity) {
306306
return (Activity) context;
307307
} else if (context instanceof ContextWrapper) {
@@ -388,15 +388,17 @@ private RequestManager fragmentGet(
388388
}
389389

390390
@NonNull
391-
SupportRequestManagerFragment getSupportRequestManagerFragment(FragmentActivity activity) {
391+
SupportRequestManagerFragment getSupportRequestManagerFragment(
392+
Context context, FragmentManager fragmentManager) {
392393
return getSupportRequestManagerFragment(
393-
activity.getSupportFragmentManager(), /*parentHint=*/ null, isActivityVisible(activity));
394+
fragmentManager, /*parentHint=*/ null, isActivityVisible(context));
394395
}
395396

396-
private static boolean isActivityVisible(Activity activity) {
397+
private static boolean isActivityVisible(Context context) {
397398
// This is a poor heuristic, but it's about all we have. We'd rather err on the side of visible
398399
// and start requests than on the side of invisible and ignore valid requests.
399-
return !activity.isFinishing();
400+
Activity activity = findActivity(context);
401+
return activity == null || !activity.isFinishing();
400402
}
401403

402404
@NonNull

‎library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java

+32-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import androidx.annotation.Nullable;
88
import androidx.annotation.VisibleForTesting;
99
import androidx.fragment.app.Fragment;
10-
import androidx.fragment.app.FragmentActivity;
10+
import androidx.fragment.app.FragmentManager;
1111
import com.bumptech.glide.Glide;
1212
import com.bumptech.glide.RequestManager;
1313
import com.bumptech.glide.util.Synthetic;
@@ -111,9 +111,22 @@ Set<SupportRequestManagerFragment> getDescendantRequestManagerFragments() {
111111
*/
112112
void setParentFragmentHint(@Nullable Fragment parentFragmentHint) {
113113
this.parentFragmentHint = parentFragmentHint;
114-
if (parentFragmentHint != null && parentFragmentHint.getActivity() != null) {
115-
registerFragmentWithRoot(parentFragmentHint.getActivity());
114+
if (parentFragmentHint == null || parentFragmentHint.getContext() == null) {
115+
return;
116116
}
117+
FragmentManager rootFragmentManager = getRootFragmentManager(parentFragmentHint);
118+
if (rootFragmentManager == null) {
119+
return;
120+
}
121+
registerFragmentWithRoot(parentFragmentHint.getContext(), rootFragmentManager);
122+
}
123+
124+
@Nullable
125+
private static FragmentManager getRootFragmentManager(@NonNull Fragment fragment) {
126+
while (fragment.getParentFragment() != null) {
127+
fragment = fragment.getParentFragment();
128+
}
129+
return fragment.getFragmentManager();
117130
}
118131

119132
@Nullable
@@ -135,10 +148,13 @@ private boolean isDescendant(@NonNull Fragment fragment) {
135148
return false;
136149
}
137150

138-
private void registerFragmentWithRoot(@NonNull FragmentActivity activity) {
151+
private void registerFragmentWithRoot(
152+
@NonNull Context context, @NonNull FragmentManager fragmentManager) {
139153
unregisterFragmentWithRoot();
140154
rootRequestManagerFragment =
141-
Glide.get(activity).getRequestManagerRetriever().getSupportRequestManagerFragment(activity);
155+
Glide.get(context)
156+
.getRequestManagerRetriever()
157+
.getSupportRequestManagerFragment(context, fragmentManager);
142158
if (!equals(rootRequestManagerFragment)) {
143159
rootRequestManagerFragment.addChildRequestManagerFragment(this);
144160
}
@@ -154,8 +170,18 @@ private void unregisterFragmentWithRoot() {
154170
@Override
155171
public void onAttach(Context context) {
156172
super.onAttach(context);
173+
174+
FragmentManager rootFragmentManager = getRootFragmentManager(this);
175+
if (rootFragmentManager == null) {
176+
if (Log.isLoggable(TAG, Log.WARN)) {
177+
// Not expected to occur; ancestor fragments should be attached before descendants.
178+
Log.w(TAG, "Unable to register fragment with root, ancestor detached");
179+
}
180+
return;
181+
}
182+
157183
try {
158-
registerFragmentWithRoot(getActivity());
184+
registerFragmentWithRoot(getContext(), rootFragmentManager);
159185
} catch (IllegalStateException e) {
160186
// OnAttach can be called after the activity is destroyed, see #497.
161187
if (Log.isLoggable(TAG, Log.WARN)) {

‎library/test/src/test/java/com/bumptech/glide/manager/RequestManagerRetrieverTest.java

+46-1
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@
1313
import android.content.Context;
1414
import android.content.ContextWrapper;
1515
import android.os.Build;
16+
import android.os.Handler;
1617
import android.os.Looper;
18+
import android.view.LayoutInflater;
19+
import androidx.annotation.Nullable;
1720
import androidx.annotation.RequiresApi;
1821
import androidx.fragment.app.Fragment;
1922
import androidx.fragment.app.FragmentActivity;
23+
import androidx.fragment.app.FragmentController;
24+
import androidx.fragment.app.FragmentHostCallback;
2025
import androidx.test.core.app.ApplicationProvider;
2126
import com.bumptech.glide.RequestManager;
2227
import com.bumptech.glide.tests.BackgroundUtil.BackgroundTester;
@@ -50,7 +55,7 @@ public class RequestManagerRetrieverTest {
5055
public void setUp() {
5156
appContext = ApplicationProvider.getApplicationContext();
5257

53-
retriever = new RequestManagerRetriever(null /*factory*/);
58+
retriever = new RequestManagerRetriever(/*factory=*/ null);
5459

5560
harnesses =
5661
new RetrieverHarness[] {new DefaultRetrieverHarness(), new SupportRetrieverHarness()};
@@ -161,6 +166,23 @@ public void testSupportCanGetRequestManagerFromFragment() {
161166
assertEquals(manager, retriever.get(fragment));
162167
}
163168

169+
@Test
170+
public void testSupportCanGetRequestManagerFromFragment_nonActivityController() {
171+
FragmentController controller =
172+
FragmentController.createController(new NonActivityHostCallback(appContext));
173+
controller.attachHost(/*fragment=*/ null);
174+
controller.dispatchCreate();
175+
controller.dispatchStart();
176+
controller.dispatchResume();
177+
178+
Fragment fragment = new Fragment();
179+
controller.getSupportFragmentManager().beginTransaction().add(fragment, PARENT_TAG).commit();
180+
controller.getSupportFragmentManager().executePendingTransactions();
181+
182+
RequestManager manager = retriever.get(fragment);
183+
assertEquals(manager, retriever.get(fragment));
184+
}
185+
164186
@Test
165187
public void testCanGetRequestManagerFromDetachedFragment() {
166188
helpTestCanGetRequestManagerFromDetachedFragment();
@@ -488,4 +510,27 @@ public void addFragmentWithTag(String tag, RequestManager manager) {
488510
controller.get().getSupportFragmentManager().executePendingTransactions();
489511
}
490512
}
513+
514+
/** Simple callback for creating an Activity-less Fragment host. */
515+
private final class NonActivityHostCallback
516+
extends FragmentHostCallback<RequestManagerRetrieverTest> {
517+
518+
private final Context context;
519+
520+
NonActivityHostCallback(Context context) {
521+
super(context, new Handler(Looper.getMainLooper()), /*windowAnimations=*/ 0);
522+
this.context = context;
523+
}
524+
525+
@Override
526+
public LayoutInflater onGetLayoutInflater() {
527+
return LayoutInflater.from(context).cloneInContext(context);
528+
}
529+
530+
@Nullable
531+
@Override
532+
public RequestManagerRetrieverTest onGetHost() {
533+
return RequestManagerRetrieverTest.this;
534+
}
535+
}
491536
}

0 commit comments

Comments
 (0)
Please sign in to comment.