Skip to content

Conversation

@largeblueberry
Copy link
Contributor

Purpose / Description

This PR addresses the memory leak issues in SharedDecksActivity related to WebView usage, as identified in #19965.

Following the experimental fix suggestions, I implemented the onDestroy() method in SharedDecksActivity and incorporated the cleanup logic based on the pattern found in SafeWebViewLayout.safeDestroy()

Fixes

Approach

The focus of this change is to ensure that the WebView is properly disposed of when the Activity is destroyed. I ported the cleanup sequence from SafeWebViewLayout:

  • Stopped ongoing loading and cleared the WebView by loading about:blank.
  • Nullified WebChromeClient and OnScrollChangeListener to break reference cycles.
  • Detached the WebView from its parent ViewGroup before final destruction.
  • Wrapped the destroy() call in runCatchingWithReport for safe execution and logging.

How Has This Been Tested?

To verify the fix, I navigated between SharedDecksActivity and DeckPicker 10 times consecutively.

Result:

API 34: Some leaks still persist, but these are attributed to the Context issue as discussed in the issue thread.
However, the specific leaks related to improper WebView teardown have been significantly mitigated.

API 35: leaks are fully resolved with this cleanup in place.

API 34

Image

API 35

Image

Learning (optional, can help others)

Confirmed that applying the SafeWebViewLayout.safeDestroy() pattern directly within an Activity's onDestroy() is an effective experimental approach to mitigate WebView-related memory leaks in AnkiDroid.

Checklist

Please, go through these checks before submitting the PR.

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner


Timber.d("Destroying WebView")

runCatchingWithReport("safeDestroy", onlyIfSilent = true) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates the following, see if there's a better abstraction which you could use:

@MainThread
fun safeDestroy() {
Timber.d("Destroying WebView")
runCatchingWithReport("safeDestroy", onlyIfSilent = true) {
webView.stopLoading()
webView.loadUrl("about:blank")
webView.webChromeClient = null
removeView(webView)
// remove listeners this class exposes
webView.setOnScrollChangeListener(null)
}
// attempt to run destroy() even if the above fails
runCatchingWithReport("safeDestroy", onlyIfSilent = true) {
webView.destroy()
}
}

@largeblueberry
Copy link
Contributor Author

I've refactored the code to centralize the WebView destruction logic into a static method within 'SafeWebViewLayout.'
This avoids code duplication while ensuring 'SharedDecksActivity' also benefits from the safe destruction process as suggested. Thanks for the feedback!"

Copy link
Member

@BrayanDSO BrayanDSO left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to use SafeWebViewLayout in SharedDecksActivity, then call safeDestroy() there

@largeblueberry
Copy link
Contributor Author

"Following your suggestion, I replaced the standard WebView with com.ichi2.anki.workarounds.SafeWebViewLayout and updated the ViewBinding to resolve compilation errors.

However, when I ran the app and navigated from DeckPicker to SharedDecksActivity, the app crashed with the following error:

java.lang.IllegalStateException: SafeWebViewLayout must be used within a Fragment

It seems SafeWebViewLayout was designed specifically for Fragments (it calls findFragment() in onAttachedToWindow).
Since SharedDecksActivity is an Activity, using this layout directly causes an issue.

Given this constraint, do you think I should refactor SafeWebViewLayout to support Activities as well, or would it be better to stick with WebView for this specific case?"

SafeWebviewLayout is only for fragment

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.

Memory leak in SharedDecksActivity (suspected WebView Context issue)

3 participants