提交 e7e7620f 编写于 作者: S Sam Judd

Avoid concurrent modification in lifecycle impl.

Fixes #375.
上级 c3ee8a28
package com.bumptech.glide.manager; package com.bumptech.glide.manager;
import com.bumptech.glide.util.Util;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.WeakHashMap; import java.util.WeakHashMap;
...@@ -44,21 +46,21 @@ class ActivityFragmentLifecycle implements Lifecycle { ...@@ -44,21 +46,21 @@ class ActivityFragmentLifecycle implements Lifecycle {
void onStart() { void onStart() {
isStarted = true; isStarted = true;
for (LifecycleListener lifecycleListener : lifecycleListeners) { for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart(); lifecycleListener.onStart();
} }
} }
void onStop() { void onStop() {
isStarted = false; isStarted = false;
for (LifecycleListener lifecycleListener : lifecycleListeners) { for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop(); lifecycleListener.onStop();
} }
} }
void onDestroy() { void onDestroy() {
isDestroyed = true; isDestroyed = true;
for (LifecycleListener lifecycleListener : lifecycleListeners) { for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy(); lifecycleListener.onDestroy();
} }
} }
......
package com.bumptech.glide.manager; package com.bumptech.glide.manager;
import com.bumptech.glide.request.Request; import com.bumptech.glide.request.Request;
import com.bumptech.glide.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
...@@ -64,7 +65,7 @@ public class RequestTracker { ...@@ -64,7 +65,7 @@ public class RequestTracker {
*/ */
public void pauseRequests() { public void pauseRequests() {
isPaused = true; isPaused = true;
for (Request request : getSnapshot()) { for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) { if (request.isRunning()) {
request.pause(); request.pause();
pendingRequests.add(request); pendingRequests.add(request);
...@@ -77,7 +78,7 @@ public class RequestTracker { ...@@ -77,7 +78,7 @@ public class RequestTracker {
*/ */
public void resumeRequests() { public void resumeRequests() {
isPaused = false; isPaused = false;
for (Request request : getSnapshot()) { for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) { if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) {
request.begin(); request.begin();
} }
...@@ -89,7 +90,7 @@ public class RequestTracker { ...@@ -89,7 +90,7 @@ public class RequestTracker {
* Cancels all requests and clears their resources. * Cancels all requests and clears their resources.
*/ */
public void clearRequests() { public void clearRequests() {
for (Request request : getSnapshot()) { for (Request request : Util.getSnapshot(requests)) {
request.clear(); request.clear();
} }
pendingRequests.clear(); pendingRequests.clear();
...@@ -99,7 +100,7 @@ public class RequestTracker { ...@@ -99,7 +100,7 @@ public class RequestTracker {
* Restarts failed requests and cancels and restarts in progress requests. * Restarts failed requests and cancels and restarts in progress requests.
*/ */
public void restartRequests() { public void restartRequests() {
for (Request request : getSnapshot()) { for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled()) { if (!request.isComplete() && !request.isCancelled()) {
// Ensure the request will be restarted in onResume. // Ensure the request will be restarted in onResume.
request.pause(); request.pause();
...@@ -111,17 +112,4 @@ public class RequestTracker { ...@@ -111,17 +112,4 @@ public class RequestTracker {
} }
} }
} }
// Avoids a ConcurrentModificationException when requests are started by another request completing. See #303.
private List<Request> getSnapshot() {
// toArray creates a new ArrayList internally and this way we can guarantee entries will not be
// null. See #322.
List<Request> result = new ArrayList<Request>(requests.size());
// We could also just call new ArrayList<Request>(requests) but that actually creates two new ArrayLists because
// that constructor in ArrayList calls toArray().
for (Request request : requests) {
result.add(request);
}
return result;
}
} }
...@@ -8,6 +8,9 @@ import android.os.Looper; ...@@ -8,6 +8,9 @@ import android.os.Looper;
import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.target.Target;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Queue; import java.util.Queue;
/** /**
...@@ -157,9 +160,25 @@ public final class Util { ...@@ -157,9 +160,25 @@ public final class Util {
} }
/** /**
* Creates a {@link java.util.Queue} of the given size using Glide's preferred implementation. * Returns a {@link java.util.Queue} of the given size using Glide's preferred implementation.
*/ */
public static <T> Queue<T> createQueue(int size) { public static <T> Queue<T> createQueue(int size) {
return new ArrayDeque<T>(size); return new ArrayDeque<T>(size);
} }
/**
* Returns a copy of the given list that is safe to iterate over and perform actions that may
* modify the original list.
*
* <p> See #303 and #375. </p>
*/
public static <T> List<T> getSnapshot(Collection<T> other) {
// toArray creates a new ArrayList internally and this way we can guarantee entries will not
// be null. See #322.
List<T> result = new ArrayList<T>(other.size());
for (T item : other) {
result.add(item);
}
return result;
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册