Fixed: testOpeningFileWithFilePicker test intermittently fails on API level 34.

* Fixed: Memory leaks in `OnlineLibraryFragment` that appeared after upgrading LeakCanary.
* Fixed: Memory leaks in `LocalFileTransferFragment` that appeared after upgrading LeakCanary.
* Fixed: A memory leak in `ZimManageViewModel` caused by `addNetworkInterceptor` holding a reference to progressListener.
This commit is contained in:
MohitMaliFtechiz 2025-03-24 17:58:22 +05:30
parent 6aa0980e4d
commit 4205fc41b7
6 changed files with 26 additions and 14 deletions

View File

@ -117,7 +117,7 @@ class OpeningFilesFromStorageTest : BaseActivityTest() {
sharedPreferenceUtil.shouldShowStorageSelectionDialog = true sharedPreferenceUtil.shouldShowStorageSelectionDialog = true
// open file picker to select a file to test the real scenario. // open file picker to select a file to test the real scenario.
composeTestRule.onNodeWithTag(SELECT_FILE_BUTTON_TESTING_TAG).performClick() composeTestRule.onNodeWithTag(SELECT_FILE_BUTTON_TESTING_TAG).performClick()
uiDevice.findObject(By.textContains(fileName)).click() TestUtils.testFlakyView(uiDevice.findObject(By.textContains(fileName))::click, 10)
copyMoveFileHandler { copyMoveFileHandler {
assertCopyMoveDialogDisplayed() assertCopyMoveDialogDisplayed()

View File

@ -533,6 +533,7 @@ class LocalFileTransferFragment :
override fun onDestroyView() { override fun onDestroyView() {
wifiDirectManager.stopWifiDirectManager() wifiDirectManager.stopWifiDirectManager()
wifiDirectManager.callbacks = null wifiDirectManager.callbacks = null
fragmentLocalFileTransferBinding?.root?.removeAllViews()
fragmentLocalFileTransferBinding = null fragmentLocalFileTransferBinding = null
searchIconView = null searchIconView = null
materialShowCaseSequence = null materialShowCaseSequence = null

View File

@ -227,14 +227,14 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
setupMenu() setupMenu()
// hides keyboard when scrolled // hides keyboard when scrolled
fragmentDestinationDownloadBinding?.libraryList?.addOnScrollListener( fragmentDestinationDownloadBinding?.libraryList?.addOnScrollListener(simpleScrollListener)
SimpleRecyclerViewScrollListener { _, newState -> }
private var simpleScrollListener = SimpleRecyclerViewScrollListener { _, newState ->
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
fragmentDestinationDownloadBinding?.libraryList?.closeKeyboard() fragmentDestinationDownloadBinding?.libraryList?.closeKeyboard()
} }
} }
)
}
private fun setupMenu() { private fun setupMenu() {
(requireActivity() as MenuHost).addMenuProvider( (requireActivity() as MenuHost).addMenuProvider(
@ -373,7 +373,12 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
fragmentDestinationDownloadBinding?.libraryList?.adapter = null fragmentDestinationDownloadBinding?.apply {
librarySwipeRefresh.setOnRefreshListener(null)
libraryList.removeOnScrollListener(simpleScrollListener)
libraryList.adapter = null
root.removeAllViews()
}
fragmentDestinationDownloadBinding = null fragmentDestinationDownloadBinding = null
} }

View File

@ -181,7 +181,7 @@ class ZimManageViewModel @Inject constructor(
.body( .body(
ProgressResponseBody( ProgressResponseBody(
responseBody, responseBody,
AppProgressListenerProvider(this), appProgressListener,
contentLength contentLength
) )
) )
@ -195,6 +195,8 @@ class ZimManageViewModel @Inject constructor(
} }
} }
private var appProgressListener: AppProgressListenerProvider? = AppProgressListenerProvider(this)
private fun getContentLengthOfLibraryXmlFile(): Long { private fun getContentLengthOfLibraryXmlFile(): Long {
val headRequest = val headRequest =
Request.Builder() Request.Builder()
@ -218,7 +220,7 @@ class ZimManageViewModel @Inject constructor(
?: DEFAULT_INT_VALUE.toLong() ?: DEFAULT_INT_VALUE.toLong()
} }
} }
} catch (ignore: Exception) { } catch (_: Exception) {
// do nothing // do nothing
} }
return DEFAULT_INT_VALUE.toLong() return DEFAULT_INT_VALUE.toLong()
@ -237,6 +239,7 @@ class ZimManageViewModel @Inject constructor(
fileSelectActions.onComplete() fileSelectActions.onComplete()
requestDownloadLibrary.onComplete() requestDownloadLibrary.onComplete()
compositeDisposable = null compositeDisposable = null
appProgressListener = null
super.onCleared() super.onCleared()
} }

View File

@ -30,7 +30,7 @@ import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
class ProgressResponseBody( class ProgressResponseBody(
private val responseBody: ResponseBody, private val responseBody: ResponseBody,
private val progressListener: OnlineLibraryProgressListener, private val progressListener: OnlineLibraryProgressListener?,
private val contentLength: Long private val contentLength: Long
) : ResponseBody() { ) : ResponseBody() {
private lateinit var bufferedSource: BufferedSource private lateinit var bufferedSource: BufferedSource
@ -51,7 +51,7 @@ class ProgressResponseBody(
override fun read(sink: Buffer, byteCount: Long): Long { override fun read(sink: Buffer, byteCount: Long): Long {
val bytesRead = super.read(sink, byteCount) val bytesRead = super.read(sink, byteCount)
totalBytesRead += if (bytesRead != DEFAULT_INT_VALUE.toLong()) bytesRead else ZERO.toLong() totalBytesRead += if (bytesRead != DEFAULT_INT_VALUE.toLong()) bytesRead else ZERO.toLong()
progressListener.onProgress(totalBytesRead, contentLength) progressListener?.onProgress(totalBytesRead, contentLength)
return bytesRead return bytesRead
} }
} }

View File

@ -189,7 +189,10 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
compositeDisposable.clear() compositeDisposable.clear()
fragmentPageBinding?.recyclerView?.adapter = null fragmentPageBinding?.apply {
recyclerView.adapter = null
root.removeAllViews()
}
fragmentPageBinding = null fragmentPageBinding = null
} }