Skip to content

Commit f010b46

Browse files
fix(storage, android): stream handler & event channel clean up on completion (#13508)
* fix(storage, android): stream handler and event channel was never cleaned up on completion causing out-of-memory exception * chore: format
1 parent 0158ad2 commit f010b46

File tree

3 files changed

+37
-19
lines changed

3 files changed

+37
-19
lines changed

packages/firebase_storage/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FlutterFirebaseStoragePlugin.java

+18-15
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ public class FlutterFirebaseStoragePlugin
4242
static final String STORAGE_TASK_EVENT_NAME = "taskEvent";
4343
static final String DEFAULT_ERROR_CODE = "firebase_storage";
4444

45-
private final Map<String, EventChannel> eventChannels = new HashMap<>();
46-
private final Map<String, StreamHandler> streamHandlers = new HashMap<>();
45+
static final Map<String, EventChannel> eventChannels = new HashMap<>();
46+
static final Map<String, StreamHandler> streamHandlers = new HashMap<>();
4747

4848
static Map<String, String> getExceptionDetails(Exception exception) {
4949
Map<String, String> details = new HashMap<>();
@@ -145,11 +145,6 @@ private void initInstance(BinaryMessenger messenger) {
145145
this.messenger = messenger;
146146
}
147147

148-
private String registerEventChannel(String prefix, StreamHandler handler) {
149-
String identifier = UUID.randomUUID().toString().toLowerCase(Locale.US);
150-
return registerEventChannel(prefix, identifier, handler);
151-
}
152-
153148
private String registerEventChannel(String prefix, String identifier, StreamHandler handler) {
154149
final String channelName = prefix + "/" + identifier;
155150

@@ -459,10 +454,12 @@ public void referencePutData(
459454
FlutterFirebaseStorageTask.uploadBytes(
460455
handle.intValue(), androidReference, data, androidMetaData);
461456
try {
462-
TaskStateChannelStreamHandler handler = storageTask.startTaskWithMethodChannel(channel);
457+
String identifier = UUID.randomUUID().toString().toLowerCase(Locale.US);
458+
TaskStateChannelStreamHandler handler =
459+
storageTask.startTaskWithMethodChannel(channel, identifier);
463460
result.success(
464461
registerEventChannel(
465-
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, handler));
462+
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, identifier, handler));
466463
} catch (Exception e) {
467464
result.error(FlutterFirebaseStorageException.parserExceptionToFlutter(e));
468465
}
@@ -489,10 +486,12 @@ public void referencePutString(
489486
androidMetaData);
490487

491488
try {
492-
TaskStateChannelStreamHandler handler = storageTask.startTaskWithMethodChannel(channel);
489+
String identifier = UUID.randomUUID().toString().toLowerCase(Locale.US);
490+
TaskStateChannelStreamHandler handler =
491+
storageTask.startTaskWithMethodChannel(channel, identifier);
493492
result.success(
494493
registerEventChannel(
495-
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, handler));
494+
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, identifier, handler));
496495
} catch (Exception e) {
497496
result.error(FlutterFirebaseStorageException.parserExceptionToFlutter(e));
498497
}
@@ -517,10 +516,12 @@ public void referencePutFile(
517516
settableMetaData == null ? null : getMetaDataFromPigeon(settableMetaData));
518517

519518
try {
520-
TaskStateChannelStreamHandler handler = storageTask.startTaskWithMethodChannel(channel);
519+
String identifier = UUID.randomUUID().toString().toLowerCase(Locale.US);
520+
TaskStateChannelStreamHandler handler =
521+
storageTask.startTaskWithMethodChannel(channel, identifier);
521522
result.success(
522523
registerEventChannel(
523-
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, handler));
524+
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, identifier, handler));
524525
} catch (Exception e) {
525526
result.error(FlutterFirebaseStorageException.parserExceptionToFlutter(e));
526527
}
@@ -540,10 +541,12 @@ public void referenceDownloadFile(
540541
handle.intValue(), androidReference, new File(filePath));
541542

542543
try {
543-
TaskStateChannelStreamHandler handler = storageTask.startTaskWithMethodChannel(channel);
544+
String identifier = UUID.randomUUID().toString().toLowerCase(Locale.US);
545+
TaskStateChannelStreamHandler handler =
546+
storageTask.startTaskWithMethodChannel(channel, identifier);
544547
result.success(
545548
registerEventChannel(
546-
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, handler));
549+
STORAGE_METHOD_CHANNEL_NAME + "/" + STORAGE_TASK_EVENT_NAME, identifier, handler));
547550
} catch (Exception e) {
548551
result.error(FlutterFirebaseStorageException.parserExceptionToFlutter(e));
549552
}

packages/firebase_storage/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/FlutterFirebaseStorageTask.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ void destroy() {
155155
}
156156
}
157157

158-
TaskStateChannelStreamHandler startTaskWithMethodChannel(@NonNull MethodChannel channel)
159-
throws Exception {
158+
TaskStateChannelStreamHandler startTaskWithMethodChannel(
159+
@NonNull MethodChannel channel, @NonNull String identifier) throws Exception {
160160
if (type == FlutterFirebaseStorageTaskType.BYTES && bytes != null) {
161161
if (metadata == null) {
162162
storageTask = reference.putBytes(bytes);
@@ -175,7 +175,7 @@ TaskStateChannelStreamHandler startTaskWithMethodChannel(@NonNull MethodChannel
175175
throw new Exception("Unable to start task. Some arguments have no been initialized.");
176176
}
177177

178-
return new TaskStateChannelStreamHandler(this, reference.getStorage(), storageTask);
178+
return new TaskStateChannelStreamHandler(this, reference.getStorage(), storageTask, identifier);
179179
}
180180

181181
public Object getSnapshot() {

packages/firebase_storage/firebase_storage/android/src/main/java/io/flutter/plugins/firebase/storage/TaskStateChannelStreamHandler.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.google.firebase.storage.FirebaseStorage;
1010
import com.google.firebase.storage.StorageException;
1111
import com.google.firebase.storage.StorageTask;
12+
import io.flutter.plugin.common.EventChannel;
1213
import io.flutter.plugin.common.EventChannel.EventSink;
1314
import io.flutter.plugin.common.EventChannel.StreamHandler;
1415
import java.util.HashMap;
@@ -18,6 +19,7 @@ public class TaskStateChannelStreamHandler implements StreamHandler {
1819
private final FlutterFirebaseStorageTask flutterTask;
1920
private final FirebaseStorage androidStorage;
2021
private final StorageTask<?> androidTask;
22+
private final String identifier;
2123

2224
private final String TASK_STATE_NAME = "taskState";
2325
private final String TASK_APP_NAME = "appName";
@@ -27,10 +29,12 @@ public class TaskStateChannelStreamHandler implements StreamHandler {
2729
public TaskStateChannelStreamHandler(
2830
FlutterFirebaseStorageTask flutterTask,
2931
FirebaseStorage androidStorage,
30-
StorageTask androidTask) {
32+
StorageTask androidTask,
33+
String identifier) {
3134
this.flutterTask = flutterTask;
3235
this.androidStorage = androidStorage;
3336
this.androidTask = androidTask;
37+
this.identifier = identifier;
3438
}
3539

3640
@Override
@@ -104,6 +108,17 @@ public void onListen(Object arguments, EventSink events) {
104108
public void onCancel(Object arguments) {
105109
if (!androidTask.isCanceled()) androidTask.cancel();
106110
if (!flutterTask.isDestroyed()) flutterTask.destroy();
111+
EventChannel eventChannel = FlutterFirebaseStoragePlugin.eventChannels.get(identifier);
112+
113+
// Remove stream handler and clear the event channel
114+
if (eventChannel != null) {
115+
eventChannel.setStreamHandler(null);
116+
FlutterFirebaseStoragePlugin.eventChannels.remove(identifier);
117+
}
118+
119+
if (FlutterFirebaseStoragePlugin.streamHandlers.get(identifier) != null) {
120+
FlutterFirebaseStoragePlugin.streamHandlers.remove(identifier);
121+
}
107122
}
108123

109124
private Map<String, Object> getTaskEventMap(

0 commit comments

Comments
 (0)