Fix some memory leaks and cleanup Repository feature

This commit is contained in:
Iamlooker 2022-06-30 00:44:26 +05:30
parent c599cbc75f
commit 615751fbb1
No known key found for this signature in database
GPG Key ID: 16F53B972BAECA48
7 changed files with 50 additions and 42 deletions

View File

@ -5,6 +5,7 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.looker.droidify.database.entity.Repository
import kotlinx.coroutines.flow.Flow
@Dao
interface RepositoryDao : BaseDao<Repository> {
@ -27,6 +28,9 @@ interface RepositoryDao : BaseDao<Repository> {
@Query("SELECT * FROM repository WHERE _id = :id")
fun getLive(id: Long): LiveData<Repository?>
@Query("SELECT * FROM repository ORDER BY _id ASC")
fun getAllRepositories(): Flow<List<Repository>>
@get:Query("SELECT * FROM repository ORDER BY _id ASC")
val all: List<Repository>
@ -38,7 +42,7 @@ interface RepositoryDao : BaseDao<Repository> {
// TODO clean up products and other tables afterwards
@Query("DELETE FROM repository WHERE _id = :id")
fun deleteById(id: Long): Int
fun deleteById(id: Long)
@Query("SELECT MAX(_id) FROM repository")
fun latestAddedId(): Long

View File

@ -43,6 +43,7 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.lang.ref.WeakReference
import kotlin.math.roundToInt
@ -117,7 +118,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
fun installApps(products: List<ProductItem>) = batchUpdate(products, true)
fun sync(request: SyncRequest) {
GlobalScope.launch {
scope.launch {
val ids = db.repositoryDao.all.filter { it.enabled }.map { it.id }.toList()
sync(ids, request)
}
@ -143,29 +144,30 @@ class SyncService : ConnectionService<SyncService.Binder>() {
}
}
fun setEnabled(repository: Repository, enabled: Boolean): Boolean {
db.repositoryDao.put(repository.enable(enabled))
if (enabled) {
if (repository.id != currentTask?.task?.repositoryId && !tasks.any { it.repositoryId == repository.id }) {
synchronized(tasks) { tasks += Task(repository.id, true) }
handleNextTask(false)
suspend fun setEnabled(repository: Repository, enabled: Boolean): Boolean =
withContext(Dispatchers.IO) {
db.repositoryDao.put(repository.enable(enabled))
if (enabled) {
if (repository.id != currentTask?.task?.repositoryId && !tasks.any { it.repositoryId == repository.id }) {
synchronized(tasks) { tasks += Task(repository.id, true) }
handleNextTask(false)
}
} else {
cancelTasks { it.repositoryId == repository.id }
synchronized(tasks) { db.cleanUp(setOf(Pair(repository.id, false))) }
val cancelledTask = cancelCurrentTask { it.task?.repositoryId == repository.id }
handleNextTask(cancelledTask?.hasUpdates == true)
}
} else {
cancelTasks { it.repositoryId == repository.id }
synchronized(tasks) { db.cleanUp(setOf(Pair(repository.id, false))) }
val cancelledTask = cancelCurrentTask { it.task?.repositoryId == repository.id }
handleNextTask(cancelledTask?.hasUpdates == true)
true
}
return true
suspend fun isCurrentlySyncing(repositoryId: Long): Boolean = withContext(Dispatchers.IO) {
currentTask?.task?.repositoryId == repositoryId
}
fun isCurrentlySyncing(repositoryId: Long): Boolean {
return currentTask?.task?.repositoryId == repositoryId
}
fun deleteRepository(repositoryId: Long): Boolean {
suspend fun deleteRepository(repositoryId: Long): Boolean = withContext(Dispatchers.IO) {
val repository = db.repositoryDao.get(repositoryId)
return repository != null && run {
repository != null && run {
setEnabled(repository, false)
db.repositoryDao.deleteById(repository.id)
true
@ -325,7 +327,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
private fun handleNextTask(hasUpdates: Boolean) {
if (currentTask == null) {
GlobalScope.launch {
scope.launch {
if (tasks.isNotEmpty()) {
val task = tasks.removeAt(0)
val repository = db.repositoryDao.get(task.repositoryId)
@ -425,7 +427,7 @@ class SyncService : ConnectionService<SyncService.Binder>() {
* @see SyncService.displayUpdatesNotification
*/
private fun batchUpdate(productItems: List<ProductItem>, install: Boolean = false) {
if (Preferences[Preferences.Key.InstallAfterSync]) GlobalScope.launch {
if (Preferences[Preferences.Key.InstallAfterSync]) scope.launch {
// run startUpdate on every item
productItems.map { productItem ->
Triple(

View File

@ -29,7 +29,7 @@ fun RepositoryPage(viewModel: RepositoriesViewModelX) {
}
}
) {
val sortedRepoList = remember { repos.sortedBy { !it.enabled } }
val sortedRepoList = remember(repos) { repos.sortedBy { !it.enabled } }
RepositoriesRecycler(
repositoriesList = sortedRepoList,
onClick = { viewModel.toggleRepository(it, it.enabled) },

View File

@ -15,6 +15,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.looker.droidify.EXTRA_REPOSITORY_ID
import com.looker.droidify.R
@ -33,9 +34,8 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
@ -138,12 +138,14 @@ class EditRepositorySheetX() : FullscreenBottomSheetDialogFragment(), RepoManage
.show(childFragmentManager)
}
GlobalScope.launch {
val list = viewModel.db.repositoryDao.all
takenAddresses = list.asSequence().filter { it.id != repositoryId }
.flatMap { (it.mirrors + it.address).asSequence() }
.map { it.withoutKnownPath }.toSet()
MainScope().launch { invalidateAddress() }
lifecycleScope.launchWhenStarted {
val reposFlow = viewModel.db.repositoryDao.getAllRepositories()
reposFlow.collectLatest { list ->
takenAddresses = list.asSequence().filter { it.id != repositoryId }
.flatMap { (it.mirrors + it.address).asSequence() }
.map { it.withoutKnownPath }.toSet()
MainScope().launch { invalidateAddress() }
}
}
}
@ -389,7 +391,7 @@ class EditRepositorySheetX() : FullscreenBottomSheetDialogFragment(), RepoManage
address: String,
fingerprint: String,
authentication: String,
) = GlobalScope.launch {
) = lifecycleScope.launch {
val binder = syncConnection.binder
if (binder != null) {
if (binder.isCurrentlySyncing(repositoryId)) {
@ -435,7 +437,7 @@ class EditRepositorySheetX() : FullscreenBottomSheetDialogFragment(), RepoManage
}
override fun onDeleteConfirm() {
GlobalScope.launch(Dispatchers.IO) {
lifecycleScope.launch {
if (syncConnection.binder?.deleteRepository(repositoryId) == true)
dismissAllowingStateLoss()
}

View File

@ -32,7 +32,7 @@ class PrefsRepositoriesFragment : BaseNavFragment() {
savedInstanceState: Bundle?,
): View {
super.onCreate(savedInstanceState)
lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenStarted {
viewModel.showSheet.collectLatest {
it?.let {
RepositorySheetX(it).showNow(childFragmentManager, "Repository $it")

View File

@ -9,6 +9,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.looker.droidify.EXTRA_REPOSITORY_ID
import com.looker.droidify.R
import com.looker.droidify.RepoManager
@ -19,8 +20,6 @@ import com.looker.droidify.service.SyncService
import com.looker.droidify.ui.activities.PrefsActivityX
import com.looker.droidify.ui.viewmodels.RepositoryViewModelX
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.util.*
@ -140,7 +139,7 @@ class RepositorySheetX() : FullscreenBottomSheetDialogFragment(), RepoManager {
}
override fun onDeleteConfirm() {
GlobalScope.launch(Dispatchers.IO) {
lifecycleScope.launch {
if (syncConnection.binder?.deleteRepository(repositoryId) == true)
dismissAllowingStateLoss()
}

View File

@ -13,6 +13,7 @@ import com.looker.droidify.service.SyncService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -30,7 +31,9 @@ class RepositoriesViewModelX(val repositoryDao: RepositoryDao) : ViewModel() {
init {
viewModelScope.launch(Dispatchers.IO) {
_repositories.emit(repositoryDao.all)
repositoryDao.getAllRepositories().collectLatest {
_repositories.emit(it)
}
}
toLaunch.value = null
}
@ -40,13 +43,11 @@ class RepositoriesViewModelX(val repositoryDao: RepositoryDao) : ViewModel() {
}
fun showRepositorySheet(repositoryId: Long) {
viewModelScope.launch {
_showSheet.emit(repositoryId)
}
viewModelScope.launch { _showSheet.emit(repositoryId) }
}
fun toggleRepository(repository: Repository, isEnabled: Boolean) {
viewModelScope.launch(Dispatchers.IO) {
viewModelScope.launch {
syncConnection.binder?.setEnabled(repository, isEnabled)
}
}