Skip to content

fix: out of memory when open large file on android - #45

Merged
vsamarth merged 1 commit into
vsamarth:mainfrom
vigov5:fix/oom-android
May 5, 2026
Merged

fix: out of memory when open large file on android#45
vsamarth merged 1 commit into
vsamarth:mainfrom
vigov5:fix/oom-android

Conversation

@vigov5

@vigov5 vigov5 commented May 5, 2026

Copy link
Copy Markdown
Contributor

The PR content was generated by AI.

fix: work around file_selector_android OOM on large file picks

Problem

Picking a large file (≥ ~195 MB) on Android crashes with:

java.lang.OutOfMemoryError: Failed to allocate a 205235072 byte allocation
  at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:120)
  at io.flutter.plugin.common.StandardMessageCodec.writeValue(...)
  at dev.flutter.packages.file_selector_android.GeneratedFileSelectorApi$PigeonCodec.writeValue(...)

Root cause: file_selector_android ≤ 0.5.2+6 reads the entire picked file into a ByteArrayOutputStream on the Java side and encodes it as a raw byte array through Flutter's StandardMessageCodec platform channel. For files larger than a few hundred MB this exhausts Android's heap before any Dart code runs.

An upstream fix has been proposed (flutter/flutter#141002) that would change the Java side to skip the byte read when a cache path is already available, and change the Dart side to prefer XFile(path) over XFile.fromData(bytes). However, the proposed Dart-only snippet is insufficient on its own — the OOM occurs on the Java side before the channel message is delivered to Dart, so both halves must ship together. No fixed release is available yet.

Solution

Bypass file_selector_android for pickFiles on Android using a direct MethodChannel implementation inside the app that never puts file bytes on the platform channel.

Flow:

  1. MainActivity registers a MethodChannel (com.example.drift/file_picker)
  2. On pickFiles, opens Intent.ACTION_OPEN_DOCUMENT (system file picker, multi-select)
  3. In onActivityResult, streams each content URI to cacheDir/drift_picked/ in 64 KB chunks via InputStream.copyTo() — no large heap allocation
  4. Returns only the resulting file-system paths to Dart
  5. On the Dart side, SendSelectionPicker.pickFiles() detects Platform.isAndroid and delegates to AndroidFilePicker; all other platforms continue using file_selector unchanged

Files changed

File Change
android/app/src/main/kotlin/…/MainActivity.kt Added MethodChannel handler with Intent.ACTION_OPEN_DOCUMENT, streaming copy to cache, filename resolution via OpenableColumns
lib/platform/android_file_picker.dart New Dart wrapper calling the channel
lib/features/send/application/send_selection_picker.dart Android branch delegates to AndroidFilePicker; non-Android path unchanged

Future cleanup

Once a fully patched file_selector_android (both Java and Dart sides) is published, the Platform.isAndroid branch in send_selection_picker.dart, android_file_picker.dart, and the MainActivity channel can all be removed and the code reverted to using openFiles() directly.

@vsamarth

vsamarth commented May 5, 2026

Copy link
Copy Markdown
Owner

Thanks a lot! Works for me as well

@vsamarth
vsamarth merged commit f840ce5 into vsamarth:main May 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants