Skip to content

Instantly share code, notes, and snippets.

@luciofm
Created May 13, 2019 16:11
Show Gist options
  • Save luciofm/3ae1c0869cf9a05cd9a2e9e5baa9c1c9 to your computer and use it in GitHub Desktop.
Save luciofm/3ae1c0869cf9a05cd9a2e9e5baa9c1c9 to your computer and use it in GitHub Desktop.
A Debouncing LiveData helper
class DebounceLiveData<Source>(
private val source: LiveData<Source>,
private val debounceMs: Long
) : LiveData<Source>(), CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
private var debounceJob: Job? = null
private val observer = Observer<Source> { source ->
debounceJob?.cancel()
debounceJob = launch {
delay(debounceMs)
value = source
}
}
override fun onActive() {
source.observeForever(observer)
}
override fun onInactive() {
debounceJob?.cancel()
source.removeObserver(observer)
}
}
fun <Source> LiveData<Source>.debounce(
time: Long,
unit: TimeUnit = TimeUnit.MILLISECONDS
): LiveData<Source> {
val timeMs = when (unit) {
TimeUnit.NANOSECONDS -> unit.toMillis(time)
TimeUnit.MICROSECONDS -> unit.toMillis(time)
TimeUnit.MILLISECONDS -> time
TimeUnit.SECONDS -> unit.toMillis(time)
TimeUnit.MINUTES -> unit.toMillis(time)
TimeUnit.HOURS -> unit.toMillis(time)
TimeUnit.DAYS -> unit.toMillis(time)
}
return DebounceLiveData(this, timeMs)
}
// Imagine you have an EditText and it emits its value (via OnQueryTextListener) to a LiveData
// Now you can debounce it to do a search.
class SearchViewModel(//depencencies) : ViewModel() {
val query: MutableLiveData<String>()
val searchResults: LiveData<List<SearchResult>>
get() = query.debounce(200).filter { it.lenght > 3 }.asyncMap { query ->
api.search(query) // Returns List<SearchResult>
}
}
class SearchFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.searchResults.observe(viewLifecycleOwner, Observer { searchResults ->
// deal with search results
})
search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextChange(newText: String): Boolean {
viewModel.query.value = newText
return false
}
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment