[Android] Never-attached ScrollView with maintainVisibleContentPosition leaks Activities
Maintainer antworten meist innerhalb von 2 Tagen
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 45/100
Rechercherichtung
Read the lifecycle handling in ReactScrollView.kt, ReactHorizontalScrollView.kt, and ReactNestedScrollView.kt, then trace helper registration in MaintainVisibleScrollPositionHelper.kt and view cleanup in the three scroll view managers. Compare the two proposed fixes linked in the issue and check existing Android scroll view manager tests. Done means a never-attached view no longer leaves its helper registered after deletion, for all three scroll view types.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Description
On Android, a ScrollView with maintainVisibleContentPosition that is mounted but never attached to a window keeps destroyed Activities in memory. In the reproducer, 10 Activity recreations (display density changes) leave 11 MainActivity instances, and all 11 are still there after 60 s idle and am send-trim-memory RUNNING_CRITICAL. Without the prop, the count drops back to 1. Without any recreation, each remount of such a ScrollView leaves one more MaintainVisibleScrollPositionHelper registered with FabricUIManager: 11 after 10 remounts.
The prop setter registers the helper as a FabricUIManager listener right away, and only onDetachedFromWindow (or setting the prop back to null) unregisters it. A view that is never attached is never detached, so the helper, its ScrollView and that view's Activity stay reachable for the life of the React instance. A ScrollView that was attached and later detached is not affected.
Where it happens: any ScrollView-based list with this prop that is mounted but never attached to a window. I found it with a list in an eagerly rendered tab that had not been shown yet. In that app, each display-size change kept the whole previous screen (about 1,200 views), and an API 29 emulator with a 48 MB heap growth limit died with OutOfMemoryError at the 11th recreation. Those two numbers come from that app, not from the reproducer. Two cases that should behave the same, not measured: a list with the prop inside a FlatList cell that is off screen from the start (removeClippedSubviews is the FlatList default on Android), and recreations caused by a font-size or language change (the template's MainActivity also leaves fontScale and locale out of configChanges).
ReactHorizontalScrollView and ReactNestedScrollView have the same code. It is unchanged on main (b16032065) and 0.89-stable (195bd5955).
In the cli info below, "Android SDK: Not Found" and "Yarn: Not Found" are wrong: the SDK (android-37.0, build-tools 37.0.0, NDK 27.1.12297006) is installed, and Yarn 1.22.22 ran through Corepack.
Steps to reproduce
Reproducer: https://github.com/nazar-pal/rn-mvcp-activity-leak-repro
The app puts a ScrollView with maintainVisibleContentPosition={{minIndexForVisible: 0}} below the bounds of a 40 dp View with removeClippedSubviews. ReactViewGroup keeps it out of the view hierarchy, so it is created and gets its props but is never attached. A button switches to the same ScrollView without the prop (control), and another remounts it.
From the repository root:
- Build and install the Release build:
(cd ReproducerApp && yarn install) (cd ReproducerApp/android && ./gradlew :app:assembleRelease) adb install -r ReproducerApp/android/app/build/outputs/apk/release/app-release.apk - Start it:
adb shell am start -W -S -n com.reproducerapp/.MainActivity - Run
ReproducerApp/scripts/recreate.sh 10. It waits for the app's UI, then recreatesMainActivity10 times by switching the display density between the current value and one 15% higher. It printsActivitiesfromdumpsys meminfoafter each recreation, after 60 s idle and after the trim. By hand:adb shell wm density 552(any value other than the current one; the API 37 emulator's is 480),adb shell wm density reset, thenadb shell dumpsys meminfo com.reproducerapp | grep Activities. - For the control, restart the app (step 2), tap Switch to control (no prop), and repeat step 3. Restart first: the Activities kept by the run with the prop stay in memory until the process ends.
- For result 2: build a debuggable Release with
(cd ReproducerApp/android && ./gradlew -I ../scripts/debuggable-release.gradle :app:assembleRelease)(a user emulator image refusesam dumpheapfor a non-debuggable app), install it, tap Remount hidden ScrollView 10 times, takeam dumpheap -g, and run the repo'stools/heap-checkon it. The README has the exact commands.
Expected: destroyed Activities are collected, as in the control. Deleted ScrollViews do not stay registered.
Actual: measured on two emulators: Android 17 / API 37 Google Play image (user build, arm64) and Android 10 / API 29 Google APIs image (userdebug build, arm64). No real device was tested.
Activities from dumpsys meminfo, official Release build, a reading 10 s after each recreation:
| Device and build | cold | after recreations 1 to 10 | 60 s idle | after trim |
|---|---|---|---|---|
| API 37 emulator, 0.88.1 Release, with the prop | 1 | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 | 11 | 11 |
| API 29 emulator, 0.88.1 Release, with the prop | 1 | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 | 11 | 11 |
| API 37 emulator, 0.89.0-rc.1 Release, with the prop | 1 | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 | 11 | 11 |
| API 37 emulator, 0.88.1 Release, control (no prop) | 1 | 2 each time | 1 | 1 |
| API 29 emulator, 0.88.1 Release, control (no prop) | 1 | 2 each time | 1 | 1 |
With the prop, Views grows by one whole view tree per recreation: 19 → 209 on API 37 and 20 → 220 on API 29. The control's 2 is the previous Activity before the next GC.
Heap dumps after a forced GC (am dumpheap -g):
| Case | Device and build | Destroyed MainActivity |
Helpers in FabricUIManager.mListeners |
|---|---|---|---|
| With prop, 4 recreations | API 37 emulator, debuggable 0.88.1 Release | 4 | 5 (4 from destroyed surfaces, 1 live) |
| With prop, 4 recreations | API 29 emulator, official 0.88.1 Release | 4 | 5 (4 from destroyed surfaces, 1 live) |
| With prop, 10 remounts, no recreation | API 37 emulator, debuggable 0.88.1 Release | 0 | 11 (10 deleted views, 1 live) |
| Control, 4 recreations and 10 remounts | API 37 emulator, debuggable 0.88.1 Release | 0 | 0 |
None of the registered helpers' ScrollViews is attached to a window or has a parent. The deleted ones are no longer in the surface's view registry. The retaining path is under Stacktrace or Logs.
Root cause
At b16032065:
ReactScrollView.kt#L397-L408: the prop setter creates the helper with.also { it.start() }, with no attach check.ReactScrollView.kt#L443-L454:onAttachedToWindowcallsstart(), andonDetachedFromWindowcallsstop(). Apart from the null-prop branch of the setter, these are the only lifecycle calls.MaintainVisibleScrollPositionHelper.kt#L72-L89:start()andstop()add the helper to and remove it from the UIManager listeners.FabricUIManager.java#L191and#L793-L800:mListenersis a strongCopyOnWriteArrayList.- Same pattern in
ReactHorizontalScrollView.kt#L438-L450andReactNestedScrollView.kt#L405-L416. - Why the reproducer's view is never attached:
ReactViewGroup.addViewWithSubviewClippingEnabledadds a child to the hierarchy only if it intersects the clipping rect.
On recreation, window teardown detaches only the views that are attached, and neither view deletion nor surface stop calls stop().
Not measured: the CPU cost of leftover helpers. FabricUIManager calls every listener on each mount (#L1009, #L1539, #L1548, #L1606). For this helper, willMountItems runs computeTargetView() and didMountItems runs updateScrollPositionInternal(); both return early when the ScrollView has no content view. didScheduleMountItems and didDispatchMountItems are no-ops.
Possible fixes
Two changes fix both results in my tests. Both diffs are against b16032065, and both are in the reproducer repo: https://github.com/nazar-pal/rn-mvcp-activity-leak-repro/blob/main/fix-stop-on-drop.diff and https://github.com/nazar-pal/rn-mvcp-activity-leak-repro/blob/main/fix-attach-check.diff.
1. Stop the helper when the view is dropped. Keep the prop setter as it is, and stop the helper in onDropViewInstance of the three scroll view managers. SurfaceMountingManager calls onDropViewInstance from both stopSurface and deleteView, through onViewStateDeleted. None of the three managers overrides it today.
Diff (fix-stop-on-drop.diff)
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.kt
@@ -74,6 +74,13 @@ constructor(private val fpsListener: FpsListener? = null) :
return preparedView
}
+ override fun onDropViewInstance(view: ReactHorizontalScrollView) {
+ // A view that was never attached to a window is never detached, so onDetachedFromWindow
+ // never stops its maintainVisibleContentPosition helper. Stop it when the view is dropped.
+ view.setMaintainVisibleContentPosition(null)
+ super.onDropViewInstance(view)
+ }
+
override fun getName(): String = REACT_CLASS
public override fun createViewInstance(context: ThemedReactContext): ReactHorizontalScrollView =
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt
@@ -83,6 +83,13 @@ constructor(private val fpsListener: FpsListener? = null) :
return preparedView
}
+ override fun onDropViewInstance(view: ReactNestedScrollView) {
+ // A view that was never attached to a window is never detached, so onDetachedFromWindow
+ // never stops its maintainVisibleContentPosition helper. Stop it when the view is dropped.
+ view.setMaintainVisibleContentPosition(null)
+ super.onDropViewInstance(view)
+ }
+
override fun getName(): String = REACT_CLASS
override fun createViewInstance(context: ThemedReactContext): ReactNestedScrollView =
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.kt
@@ -75,6 +75,13 @@ constructor(private val fpsListener: FpsListener? = null) :
return preparedView
}
+ override fun onDropViewInstance(view: ReactScrollView) {
+ // A view that was never attached to a window is never detached, so onDetachedFromWindow
+ // never stops its maintainVisibleContentPosition helper. Stop it when the view is dropped.
+ view.setMaintainVisibleContentPosition(null)
+ super.onDropViewInstance(view)
+ }
+
override fun getName(): String = REACT_CLASS
public override fun createViewInstance(context: ThemedReactContext): ReactScrollView =
2. Start the helper only when the view is attached. In the prop setter of the three scroll views, call start() only if isAttachedToWindow. onAttachedToWindow already starts it otherwise, and onDetachedFromWindow still stops it. The diff also updates the KDoc of start(), which says it should be called when the helper is created.
Diff (fix-attach-check.diff)
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt
@@ -69,7 +69,10 @@ internal class MaintainVisibleScrollPositionHelper<ScrollViewT>(
}
}
- /** Start listening to view hierarchy updates. Should be called when this is created. */
+ /**
+ * Start listening to view hierarchy updates. Called while the scroll view is attached to a
+ * window, so that a view that is never attached is never registered.
+ */
fun start() {
if (isListening) {
return
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt
@@ -441,7 +441,11 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) :
if (config != null && maintainVisibleContentPositionHelper == null) {
val helper = MaintainVisibleScrollPositionHelper(this, true)
maintainVisibleContentPositionHelper = helper
- helper.start()
+ // onAttachedToWindow starts the helper. Starting it here as well would register a view that
+ // is never attached with the UIManager, and nothing would ever unregister it.
+ if (isAttachedToWindow) {
+ helper.start()
+ }
} else if (config == null) {
maintainVisibleContentPositionHelper?.stop()
maintainVisibleContentPositionHelper = null
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt
@@ -406,8 +406,13 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) :
config: MaintainVisibleScrollPositionHelper.Config?,
) {
if (config != null && maintainVisibleContentPositionHelper == null) {
- maintainVisibleContentPositionHelper =
- MaintainVisibleScrollPositionHelper(this, false).also { it.start() }
+ val helper = MaintainVisibleScrollPositionHelper(this, false)
+ maintainVisibleContentPositionHelper = helper
+ // onAttachedToWindow starts the helper. Starting it here as well would register a view that
+ // is never attached with the UIManager, and nothing would ever unregister it.
+ if (isAttachedToWindow) {
+ helper.start()
+ }
} else if (config == null && maintainVisibleContentPositionHelper != null) {
maintainVisibleContentPositionHelper?.stop()
maintainVisibleContentPositionHelper = null
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt
@@ -398,8 +398,13 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) :
config: MaintainVisibleScrollPositionHelper.Config?,
) {
if (config != null && maintainVisibleContentPositionHelper == null) {
- maintainVisibleContentPositionHelper =
- MaintainVisibleScrollPositionHelper(this, false).also { it.start() }
+ val helper = MaintainVisibleScrollPositionHelper(this, false)
+ maintainVisibleContentPositionHelper = helper
+ // onAttachedToWindow starts the helper. Starting it here as well would register a view that
+ // is never attached with the UIManager, and nothing would ever unregister it.
+ if (isAttachedToWindow) {
+ helper.start()
+ }
} else if (config == null && maintainVisibleContentPositionHelper != null) {
maintainVisibleContentPositionHelper?.stop()
maintainVisibleContentPositionHelper = null
Measured on the API 37 emulator, Release with the prop (debuggable Release for the heap dumps). I tested each change by recompiling the changed classes against the official 0.88.1 react-android AAR and building the reproducer against that patched AAR; it was not a full source build.
| Build | Activities after 10 recreations, after 60 s idle, after trim |
Helpers in mListeners after 10 remounts |
Position check, left and right list |
|---|---|---|---|
| Official 0.88.1 | 11, 11, 11 | 11 | 0 px, 0 px |
| 1. Stop on drop | 2, 1, 1 | 1 (the live hidden ScrollView) | 0 px, 0 px |
| 2. Attach check | 2, 1, 1 | 0 | 0 px, 0 px |
| 1 and 2 together | 2, 1, 1 | 0 | 0 px, 0 px |
| Official 0.88.1, lists without the prop | 488 px, 487 px |
With each fixed build, a heap dump after 4 recreations held 0 destroyed MainActivity. The position check is a small test app (tools/mvcp-behaviour-App.tsx in the repo): one list attached at mount (left), one inside a clipping parent that is attached later (right). Both are scrolled by about two rows, then five rows are prepended; 0 px means the same row stayed in place. The row positions were read from uiautomator dump bounds; that driver script is not in the repo.
Behaviour difference: with 1, a ScrollView that is mounted but never attached stays registered, and its helper keeps running on every mount, until the view is dropped. That is today's behaviour. With 2, such a ScrollView does not listen, so it does not adjust its scroll position while detached, as is already the case for a ScrollView that was attached and then detached.
I would propose 1 first. It fixes both results in these measurements without changing behaviour, and it matches the helper's own lifecycle as documented: start when created, stop "before this is destroyed". 2 is a separate choice about whether a never-attached view should listen at all; it can be added on top, and together they left 0 helpers.
Note on tests: the unit tests added in the open PRs #58187 and #58695 set the prop and then capture the listener from addUIManagerEventListener. #58187 never attaches its ReactScrollView, so with fix 2 that test would need to attach the view first (or call onAttachedToWindow). #58695 attaches it with activity.setContentView before setting the prop. Fix 1 does not change when the listener is added. I read these tests but did not run them.
Related: initView(), which view recycling calls, sets the helper to null without calling stop() (ReactScrollView.kt#L259, ReactHorizontalScrollView.kt#L292, ReactNestedScrollView.kt#L267). That only matters for a helper that is still registered when its view is recycled, and recycling (enableViewRecyclingForScrollView) is off by default. Fix 1 stops the helper before super.onDropViewInstance() reaches the recycling code. I did not test recycling, horizontal or nested scroll views at runtime (only compiled), or real devices.
I can open a PR with this change if that would help.
React Native Version
0.88.1
Affected Platforms
Runtime - Android, Build - MacOS
Areas
Fabric - The New Renderer
Output of npx @react-native-community/cli info
System:
OS: macOS 27.2
CPU: (15) arm64 Apple M5 Pro
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.23.2
Yarn: Not Found
npm:
version: 10.9.8
Watchman:
version: 2026.06.22.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 27.2
- iOS 27.2
- macOS 27.2
- tvOS 27.2
- visionOS 27.2
- watchOS 27.2
Android SDK: Not Found
IDEs:
Android Studio: 2026.2 AI-262.10968.63.2622.16730706
Xcode:
version: 27.2/27B52
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.19
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 20.2.0
wanted: 20.2.0
react:
installed: 19.3.0
wanted: 19.3.0
react-native:
installed: 0.88.1
wanted: 0.88.1
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: Not found
newArchEnabled: false
Stacktrace or Logs
No crash in the reproducer. Retaining path after 4 recreations with the prop, from the repo's
tools/heap-check (Shark 2.14 HeapAnalyzer). It is the same on the API 37 emulator (debuggable
Release) and the API 29 emulator (official Release). Each destroyed Activity sits behind its own
entry of the listener array, one per leaked ScrollView.
MainActivity instances: 5 (destroyed: 4)
MaintainVisibleScrollPositionHelper instances: 5 (in FabricUIManager.mListeners: 5; their scroll views attached to a window: 0, with a parent: 0)
Shortest path from a GC root, the same for 4 destroyed MainActivity (array entries [0] [1] [2] [3]):
GC root: JNI_GLOBAL
com.facebook.react.fabric.FabricUIManager.mListeners
java.util.concurrent.CopyOnWriteArrayList.array
java.lang.Object[] [i]
com.facebook.react.views.scroll.MaintainVisibleScrollPositionHelper.scrollView
com.facebook.react.views.scroll.ReactScrollView.mContext
com.facebook.react.uimanager.ThemedReactContext.mBase
com.reproducerapp.MainActivity (mDestroyed = true)
Destroyed MainActivity reachable: 4
Destroyed MainActivity reachable with FabricUIManager.mListeners ignored: 0
MANDATORY Reproducer
https://github.com/nazar-pal/rn-mvcp-activity-leak-repro
Screenshots and Videos
Not visual: the leaked ScrollView is never on screen.
I used an AI assistant (Claude) to investigate this and to write the report. The measurements were taken on the simulators and emulators described above.
- Vorherrschende Sprache
- C++
- Sterne
- 127k
- Forks
- 25.5k
- Ø Merge
- 3 T. 18 Std.
- Gemergte PRs (30 T.)
- 188
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus react/react-native
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
react/react-native#59945 ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
react/react-native#59944 ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
react/react-native#59942 ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
react/react-native#59939 ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
react/react-native#59929 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 2 Tagen
Alle Issues in react/react-native
Ähnliche Issues
-
test(tools): two testkit cache tests fail unless GOCACHE and GOMODCACHE are in the environmentOffenbacklog
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
EchoTools/nevr-runtime#2385 ·
Maintainer antworten meist innerhalb von 1 Tag
-
type:bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
tensorflow/tflite-micro#3995 ·
Maintainer antworten meist innerhalb von 1 Tag
-
CPU update 1.31xOffenspeed-report
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 75/100
mw00/project-maya#961 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
-
not for AI lovers
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
OSGeo/gdal#15515 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag