Skip to content

fix: UninitializedPropertyAccessException in ImageFragment onDestroy#6661

Merged
RitikaPahwa4444 merged 3 commits intocommons-app:mainfrom
Kota-Jagadeesh:fix/custom-selector-image-fragment-crash
Feb 22, 2026
Merged

fix: UninitializedPropertyAccessException in ImageFragment onDestroy#6661
RitikaPahwa4444 merged 3 commits intocommons-app:mainfrom
Kota-Jagadeesh:fix/custom-selector-image-fragment-crash

Conversation

@Kota-Jagadeesh
Copy link
Collaborator

Description (required)

Fixes #6660

The app was crashing with a kotlin.UninitializedPropertyAccessException when a user pressed the "Back" button while images were still loading in the Custom Selector.

Changes made:

  • Added a ::filteredImages.isInitialized check in the onDestroy method of ImageFragment.
  • so, this ensures that the fragment only attempts to access the filteredImages and save the last visible item ID if the background loading process has successfully completed and initialized the property.

Tests performed (required)

Tested ProDebug on Redmi Note 13 Pro with API level 35 (Android 15).

Followed the steps mentioned in the issue #6660, and verified that the app no more crashes and safely returns to the custom selector after pressing back from the folder which i entereed.

Screenshots (for UI changes only)
N/A

@RitikaPahwa4444
Copy link
Collaborator

Curious: when do we not initialise this property? What's the actual root cause for getting this exception?

@Kota-Jagadeesh
Copy link
Collaborator Author

Kota-Jagadeesh commented Feb 22, 2026

What's the actual root cause for getting this exception?

here the property remains uninitialized if the onDestroy is triggered while the images are still in the fetching state. in ImageFragment.kt, filteredImages is assigned only within the sucess block of the handleResult, a rapid back-press triggers the onDestroy before the ViewModel and can post the SUCCESS result, causing the lateint access to fail

@RitikaPahwa4444
Copy link
Collaborator

I don't get this crash, so I'm not sure if this is really causing the problem. I'll check on a few emulators and get back to you.

@Kota-Jagadeesh
Copy link
Collaborator Author

I don't get this crash

steps :

  1. Open the app and select Custom Selector
  2. Navigate to any folder (e.g., Downloads)
  3. Select an image and click upload -> Media Details screen opens
  4. Cancel upload -> You are redirected to Contributions screen
  5. Open Custom Selector again
  6. now you will be automatically navigated into the same folder (e.g., Downloads)
  7. Before images finish loading, press back (button or swipe)
  8. The app crashes

I'll try to poste a screen record on how the crash is reproducble 🙂

#6660

@RitikaPahwa4444
Copy link
Collaborator

I've seen the issue already and tried those steps, seen your recording as well. It's not reproducible on my device.

@Kota-Jagadeesh
Copy link
Collaborator Author

I've seen the issue already and tried those steps, seen your recording as well. It's not reproducible on my device.

ohh, i'll recheck once on other devices and let you know about it :)

@Kota-Jagadeesh
Copy link
Collaborator Author

I tested this on freshly installing the app

Screenrecorder-2026-02-22-10-47-48-458.mp4

@RitikaPahwa4444
Copy link
Collaborator

We run this else block and initialise an empty array list: https://github.com/Kota-Jagadeesh/apps-android-commons/blob/32c6a8d6d474a44979f7de4b7d5b76ba43f4a64a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt#L347. Why do we need a lateinit when we can initialise it? 🙂

@Kota-Jagadeesh
Copy link
Collaborator Author

Why do we need a lateinit when we can initialise it? 🙂

yeah, right :). while the line 347 handles the empty case during the result, the race condition occurs because the onDestroy runs before any result is ever posted. to address this systematically and remove the need for isInitialized checks, i’ll refactor the filteredImages to be initialized immediately. so, thhis ensures the property is always safe to access, even during a rapid exit

@Kota-Jagadeesh
Copy link
Collaborator Author

Kota-Jagadeesh commented Feb 22, 2026

I am planing to modify the property declaration in the imagefragment to initialise it immediately and remove the lateint keyword.

from this :

lateinit var filteredImages: ArrayList<Image>

to this :

var filteredImages: ArrayList<Image> = arrayListOf()

@RitikaPahwa4444
Copy link
Collaborator

By any chance, are we using it in other classes? If not, we can make it private.

@Kota-Jagadeesh
Copy link
Collaborator Author

we can make it private.

planning the same, and verified that filteredImages is not used in other classes; the similar naming in tha iimageHelper is local to a static function. i will refactor the property to be private and initialized it immediately as an empty ArrayList to safely resolve the race condition without lateinit checks, thank you 🙂

@RitikaPahwa4444
Copy link
Collaborator

Thanks!

Just a tip: whenever you feel tempted to add a defensive check, think why we even need it and if there's a bigger problem. Defensive checks just hide such problems and we get surprises when they're unveiled somewhere else 🙂

@github-actions
Copy link

✅ Generated APK variants!

@RitikaPahwa4444
Copy link
Collaborator

Tested on an emulator. Just to confirm - does pressing back now take you to the outer directory?

@Kota-Jagadeesh
Copy link
Collaborator Author

Tested on an emulator. Just to confirm - does pressing back now take you to the outer directory?

yeah, tested again and the crash no more occurs, and it safely retuns to the custom selctorr view 🙂

and thanks for the tip @RitikaPahwa4444 , i'll definitely keep that in mind to prioritize fixing the root cause over the adding defensive layers in the future!

@RitikaPahwa4444 RitikaPahwa4444 merged commit 3e3bb69 into commons-app:main Feb 22, 2026
2 checks passed
@RitikaPahwa4444
Copy link
Collaborator

@Kota-Jagadeesh, do we still need the line I'd pointed before: https://github.com/Kota-Jagadeesh/apps-android-commons/blob/32c6a8d6d474a44979f7de4b7d5b76ba43f4a64a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt#L347? We're initialising it in the beginning and not reassigning anywhere I guess? 🤔

@Kota-Jagadeesh
Copy link
Collaborator Author

We're initialising it in the beginning and not reassigning anywhere

yeah @RitikaPahwa4444, as filteredImages is now initiaalised at the class level reassigning is indeed redundant. and for this i am thinking to just remove it and clear the list, what do you think ?

@RitikaPahwa4444
Copy link
Collaborator

RitikaPahwa4444 commented Feb 27, 2026

I'm not sure if we need to clear the list or if it will be empty already, will have to check the code.

@Kota-Jagadeesh
Copy link
Collaborator Author

if we need to clear the list or if it will be empty already,

from the handleResult logic, here when the images.isNotEmpty() is false (the else block), the list will be empty already because it came from result.images, which was just checked for the emptyness.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Crash when returning from custom selector while folder images are loading

2 participants