Introduced a mutex to manage concurrency in the search functionality. This enables proper clearing of the first running job before executing a new one. By implementing this approach, we ensure that access to the libzim search results occurs one at a time, resolving the crashing issue caused by multiple attempts to access libzim resources.

* Replaced the `cancel` function for the Job with `cancelAndJoin`, ensuring that it thoroughly cancels the first job before initiating the new task.
This commit is contained in:
MohitMaliFtechiz 2023-12-12 15:31:53 +05:30
parent 6d5e50d0ef
commit a07bb680c3

View File

@ -43,7 +43,10 @@ import androidx.recyclerview.widget.RecyclerView
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.base.BaseActivity
@ -86,6 +89,7 @@ class SearchFragment : BaseFragment() {
private var searchAdapter: SearchAdapter? = null private var searchAdapter: SearchAdapter? = null
private var isDataLoading = false private var isDataLoading = false
private var renderingJob: Job? = null private var renderingJob: Job? = null
private val searchMutex = Mutex()
override fun inject(baseActivity: BaseActivity) { override fun inject(baseActivity: BaseActivity) {
baseActivity.cachedComponent.inject(this) baseActivity.cachedComponent.inject(this)
@ -252,22 +256,25 @@ class SearchFragment : BaseFragment() {
) )
} }
private fun render(state: SearchState) { private suspend fun render(state: SearchState) {
renderingJob?.cancel() searchMutex.withLock {
isDataLoading = false // `cancelAndJoin` cancels the previous running job and waits for it to completely cancel.
searchInTextMenuItem?.isVisible = state.searchOrigin == FromWebView renderingJob?.cancelAndJoin()
searchInTextMenuItem?.isEnabled = state.searchTerm.isNotBlank() isDataLoading = false
fragmentSearchBinding?.searchLoadingIndicator?.isShowing(true) searchInTextMenuItem?.isVisible = state.searchOrigin == FromWebView
renderingJob = searchViewModel.viewModelScope.launch(Dispatchers.Main) { searchInTextMenuItem?.isEnabled = state.searchTerm.isNotBlank()
val searchResult = withContext(Dispatchers.IO) { fragmentSearchBinding?.searchLoadingIndicator?.isShowing(true)
state.getVisibleResults(0, renderingJob) renderingJob = searchViewModel.viewModelScope.launch(Dispatchers.Main) {
} val searchResult = withContext(Dispatchers.IO) {
state.getVisibleResults(0, renderingJob)
}
fragmentSearchBinding?.searchLoadingIndicator?.isShowing(false) fragmentSearchBinding?.searchLoadingIndicator?.isShowing(false)
searchResult?.let { searchResult?.let {
fragmentSearchBinding?.searchNoResults?.isVisible = it.isEmpty() fragmentSearchBinding?.searchNoResults?.isVisible = it.isEmpty()
searchAdapter?.items = it searchAdapter?.items = it
}
} }
} }
} }