Skip to content

Instantly share code, notes, and snippets.

View objcode's full-sized avatar

Sean McQuillan objcode

  • Mountain View, CA
View GitHub Profile
@objcode
objcode / Database.kt
Created May 21, 2019 01:50
Implement a one shot request with coroutines (@dao)
@Dao
interface ProductsDao {
// Because this is marked suspend, Room will use it's own dispatcher
// to run this query in a main-safe way.
@Query("select * from ProductListing ORDER BY dateStocked ASC")
suspend fun loadProductsByDateStockedAscending(): List<ProductListing>
// Because this is marked suspend, Room will use it's own dispatcher
// to run this query in a main-safe way.
@Query("select * from ProductListing ORDER BY dateStocked DESC")
@objcode
objcode / Solution0.kt
Last active May 23, 2019 09:52
Disable the buttons while a sort is running
// Solution 0: Disable the sort buttons when any sort is running
class ProductsViewModel(val productsRepository: ProductsRepository): ViewModel() {
private val _sortedProducts = MutableLiveData<List<ProductListing>>()
val sortedProducts: LiveData<List<ProductListing>> = _sortedProducts
private val _sortButtonsEnabled = MutableLiveData<Boolean>()
val sortButtonsEnabled: LiveData<Boolean> = _sortButtonsEnabled
init {
@objcode
objcode / CancelPrevious.kt
Created May 21, 2019 02:03
Use cancelPreviousThenRun to control concurrency
// Solution #1: Cancel previous work
// This is a great solution for tasks like sorting and filtering that
// can be cancelled if a new request comes in.
class ProductsRepository(val productsDao: ProductsDao, val productsApi: ProductsService) {
var controlledRunner = ControlledRunner<List<ProductListing>>()
suspend fun loadSortedProducts(ascending: Boolean): List<ProductListing> {
// cancel the previous sorts before starting a new one
@objcode
objcode / cancelPreviousThenRun.kt
Last active May 21, 2019 08:00
Example version of cancelPreviosThenRun.
// see the complete implementation at
// https://gist.github.com/objcode/7ab4e7b1df8acd88696cb0ccecad16f7
suspend fun cancelPreviousThenRun(block: suspend () -> T): T {
// If there is an activeTask, cancel it because it's result is no longer needed
activeTask?.cancelAndJoin()
// ...
@objcode
objcode / UseAfterPrevious.kt
Created May 21, 2019 02:12
Use afterPrevious to ensure one sort runs at a time.
// Solution #2: Add a Mutex
// Note: This is not optimal for the specific use case of sorting
// or filtering but is a good pattern for network saves.
class ProductsRepository(val productsDao: ProductsDao, val productsApi: ProductsService) {
val singleRunner = SingleRunner()
suspend fun loadSortedProducts(ascending: Boolean): List<ProductListing> {
// wait for the previous sort to complete before starting a new one
@objcode
objcode / UseJoinOnPrevious.kt
Created May 21, 2019 02:18
Run one network request at a time using joinOnPrevious
class ProductsRepository(val productsDao: ProductsDao, val productsApi: ProductsService) {
var controlledRunner = ControlledRunner<List<ProductListing>>()
suspend fun fetchProductsFromBackend(): List<ProductListing> {
// if there's already a request running, return the result from the
// existing request. If not, start a new request by running the block.
return controlledRunner.joinPreviousOrRun {
val result = productsApi.getProducts()
productsDao.insertAll(result)
result
@objcode
objcode / joinPreviousOrRun.kt
Created May 21, 2019 06:56
Showing the start of joinPreviosOrRun
// see the complete implementation at
// https://gist.github.com/objcode/7ab4e7b1df8acd88696cb0ccecad16f7#file-concurrencyhelpers-kt-L124
suspend fun joinPreviousOrRun(block: suspend () -> T): T {
// if there is an activeTask, return it's result and don't run the block
activeTask?.let {
return it.await()
}
// ...
@objcode
objcode / possible_cameras.py
Created July 29, 2019 19:35
Solving a very serious problem.
#!/usr/bin/env python
from collections import namedtuple
CoC = 0.018 # canon APS-C
MIN_DISTANCE = 100 # must focus 300mm away
MAX_DISTANCE = 1 * 1000 * 1000 # must focus one KM away
FOCALS = [1.3 + (x/10.0) for x in xrange(1, 40 * 10)]
FOCUS_DISTANCE = [100 * x for x in xrange(1, 10)]
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".AwesomeActivity">
<Button
// Using view binding in an Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityAwesomeBinding.inflate(layoutInflater)
binding.title.text = "Hello"
binding.subtext.text = "Concise, safe code"
binding.button.setOnClickListener { /* ... */ }
setContentView(binding.root)