Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed usage of mutex with update method of mutable state flow to atomically update values of it. #1028

Merged
merged 2 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import com.example.jetnews.utils.addOrRemove
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.flow.update

/**
* Implementation of InterestRepository that returns a hardcoded list of
Expand Down Expand Up @@ -78,9 +77,6 @@ class FakeInterestsRepository : InterestsRepository {
private val selectedPeople = MutableStateFlow(setOf<String>())
private val selectedPublications = MutableStateFlow(setOf<String>())

// Used to make suspend functions that read and update state safe to call from any thread
private val mutex = Mutex()

override suspend fun getTopics(): Result<List<InterestSection>> {
return Result.Success(topics)
}
Expand All @@ -94,26 +90,20 @@ class FakeInterestsRepository : InterestsRepository {
}

override suspend fun toggleTopicSelection(topic: TopicSelection) {
mutex.withLock {
val set = selectedTopics.value.toMutableSet()
set.addOrRemove(topic)
selectedTopics.value = set
selectedTopics.update {
it.addOrRemove(topic)
}
}

override suspend fun togglePersonSelected(person: String) {
mutex.withLock {
val set = selectedPeople.value.toMutableSet()
set.addOrRemove(person)
selectedPeople.value = set
selectedPeople.update {
it.addOrRemove(person)
}
}

override suspend fun togglePublicationSelected(publication: String) {
mutex.withLock {
val set = selectedPublications.value.toMutableSet()
set.addOrRemove(publication)
selectedPublications.value = set
selectedPublications.update {
it.addOrRemove(publication)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.withContext

/**
Expand Down Expand Up @@ -55,8 +56,6 @@ class BlockingFakePostsRepository : PostsRepository {
override fun observeFavorites(): Flow<Set<String>> = favorites

override suspend fun toggleFavorite(postId: String) {
val set = favorites.value.toMutableSet()
set.addOrRemove(postId)
favorites.value = set
favorites.update { it.addOrRemove(postId) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,22 @@ import com.example.jetnews.model.Post
import com.example.jetnews.model.PostsFeed
import com.example.jetnews.utils.addOrRemove
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.withContext

/**
* Implementation of PostsRepository that returns a hardcoded list of
* posts with resources after some delay in a background thread.
*/
@OptIn(ExperimentalCoroutinesApi::class)
class FakePostsRepository : PostsRepository {

// for now, store these in memory
private val favorites = MutableStateFlow<Set<String>>(setOf())

// Used to make suspend functions that read and update state safe to call from any thread
private val mutex = Mutex()

override suspend fun getPost(postId: String?): Result<Post> {
return withContext(Dispatchers.IO) {
Expand All @@ -68,10 +64,8 @@ class FakePostsRepository : PostsRepository {
override fun observeFavorites(): Flow<Set<String>> = favorites

override suspend fun toggleFavorite(postId: String) {
mutex.withLock {
val set = favorites.value.toMutableSet()
set.addOrRemove(postId)
favorites.value = set.toSet()
favorites.update {
it.addOrRemove(postId)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import com.example.jetnews.utils.ErrorMessage
import java.util.UUID
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
Expand Down Expand Up @@ -127,7 +126,7 @@ class HomeViewModel(

// UI state exposed to the UI
val uiState = viewModelState
.map { it.toUiState() }
.map(HomeViewModelState::toUiState)
.stateIn(
viewModelScope,
SharingStarted.Eagerly,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package com.example.jetnews.utils

internal fun <E> MutableSet<E>.addOrRemove(element: E) {
internal fun <E> Set<E>.addOrRemove(element: E): Set<E> {
this as MutableSet
if (!add(element)) {
remove(element)
}
return this.toSet()
}