Skip to content

Instantly share code, notes, and snippets.

View ZakTaccardi's full-sized avatar

Zak Taccardi ZakTaccardi

View GitHub Profile
@ZakTaccardi
ZakTaccardi / NoInitialStateFlow.kt
Created May 9, 2020 01:26
NoInitialStateFlow.kt
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
/**
* A variant of [StateFlow] that allows an initial state
*/
interface NoInitialStateFlow<T> : Flow<T> {
/**
@ZakTaccardi
ZakTaccardi / SimpleMvi.kt
Last active May 22, 2020 16:12
Simple MVI coroutine example
interface MviViewModel<in I, out VS, out SE> {
val states: Flow<VS>
val sideEffects: Flow<SE>
fun send(intention: I)
}
class SimpleViewModel(scope: CoroutineScope) : MviViewModel<Intention, State, SideEffect> {
private val _states = MutableStateFlow(0) // this is an always have an initial state example
private val _sideEffects = Channel<SideEffect>(capacity = Channel.UNLIMITED) // we don't want the actor coroutine to ever suspend, in case there is no UI consuming
@ZakTaccardi
ZakTaccardi / 1-ManualFragment.kt
Created May 20, 2020 17:22
A practical example on why Composition over Inheritance matters for your codebase
/**
* Solution 1 = Manual
*/
internal class MyManualFragment(
private val viewModel: ViewModel
) : Fragment() {
private var startedScope: CoroutineScope? = null
override fun onStart() {
@ZakTaccardi
ZakTaccardi / DontBreakTheChainTest.kt
Last active May 7, 2020 19:56
Don't break the chain
package com.capitalone.android.coroutines
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import kotlinx.coroutines.runBlocking
import org.junit.Test
import kotlin.coroutines.ContinuationInterceptor
import kotlinx.coroutines.CompletionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.flow.Flow
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
interface StateActor<S, I> : SendChannel<I> {
@ZakTaccardi
ZakTaccardi / CoroutineScope.md
Created April 22, 2020 20:52
Don't break the chain

PSA, don’t construct new CoroutineScopes and break structured concurrency in your classes.

class TransactionsDb(dispatchers: MyDispatchers) {
  private val scope = CoroutineScope(dispatchers.io)
}

This can cause tests to pass when an exception is thrown.

@ZakTaccardi
ZakTaccardi / Scoping.kt
Created March 25, 2020 18:57
scoping of data
typealias Session = String
typealias SessionId = String
// Global Graph
interface GlobalGraph {
val sessionCache: SessionCache
}
// 1 - Global state
// globalGraph.sessionCache.getCurrentSession()
@ZakTaccardi
ZakTaccardi / AddTest.kt
Created October 6, 2019 19:54
Companion Code to - Writing Awesome Tests (Coroutine Edition)
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.withContext
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
// function to test
suspend fun Int.add(valueToAdd: Int): Int = withContext(Dispatchers.Default) {
// pretend this is an expensive operation, so we switch off the main thread
@ZakTaccardi
ZakTaccardi / TestDelegate.kt
Last active October 6, 2019 19:49
Companion Code to - Writing Awesome Tests - https://medium.com/p/b271c7838344
import org.assertj.core.api.Assertions
import org.junit.Before
import org.junit.Test
// function to test
fun Int.add(valueToAdd: Int): Int = this + valueToAdd
class AddTest {
private lateinit var test: TestDelegate
@file:Suppress("unused", "FunctionName", "IllegalIdentifier")
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
/**
* The best way to launch yourself an activity. Your implementation should enable the following api: