An observables framework for Kotlin

Overview

Snail-Kotlin 🐌 Bitrise codecov

A lightweight observables framework, also available in Swift

Download

You can download a jar from GitHub's releases page.

Jitpack

allprojects {
 repositories {
    ...
    maven { url "https://jitpack.io" }
 }
}

dependencies {
  compile 'com.github.urbancompass:snail-kotlin:x.x.x'
}

Creating Observables

val observable = Observable<thing>()

Subscribing to Observables

observable.subscribe(
    next = { thing in ... }, // do something with thing
    error = { error in ... }, // do something with error
    done = { ... } // do something when it's done
)

Closures are optional too...

observable.subscribe(
    next = { thing in ... } // do something with thing
)
observable.subscribe(
    error = { error in ... } // do something with error
)

Creating Observables Variables

val variable = Variable<whatever>(some initial value)
val optionalString = Variable<String?>(null)
optionalString.asObservable().subscribe(
    next = { string in ... } // do something with value changes
)

optionalString.value = "something"
val int = Variable<Int>(12)
int.asObservable().subscribe(
    next = { int in ... } // do something with value changes
)

int.value = 42

Miscellaneous Observables

val just = Just(1) // always returns the initial value (1 in this case)

val failure = Fail(RunTimeException()) // always returns error
failure.subscribe(
	error = { it }  //it is RuntimeException
)

val n = 5
let replay = Replay(n) // replays the last N events when a new observer subscribes

Dispatchers

You can specify which dispatcher an observables will be notified on by using .subscribe(dispatcher: <desired dispatcher>). If you don't specify, then the observable will be notified on the same dispatcher that the observable published on.

There are 3 scenarios:

  1. You don't specify the dispatcher. Your observer will be notified on the same dispatcher as the observable published on.

  2. You specified Main dispatcher AND the observable published on the Main dispatcher. Your observer will be notified synchronously on the Main dispatcher.

  3. You specified a dispatcher. Your observer will be notified async on the specified dispatcher.

Examples

Subscribing on Main

observable.subscribe(Dispatchers.Main, next = {
    // do stuff with it...
})
Comments
  • Fix concurrency bug in Replay

    Fix concurrency bug in Replay

    JIRA

    https://compass-tech.atlassian.net/browse/CEI-504

    Summary

    • Replay has a concurrency bug. When multiple subscribers are posting values to it from different threads, we can hit an index out of bounds exception.
    • This is causing a semi-major bug in the offline banner feature on Android.
    • Adds a test (that breaks without the changes) and fixes Replay by adding concurrency locks around the internal values list.

    Stacktrace

    Fatal Exception: java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
           at java.util.ArrayList.add(ArrayList.java:468)
           at com.compass.snail.Replay.next(Replay.kt:17)
           at com.compass.snail.Variable.setValue(Variable.kt:18)
           at com.compass.compasslibrary.services.NetworkBroadcastReceiverService.updateConnection(NetworkBroadcastReceiverService.kt:42)
           at com.compass.compasslibrary.apiv3.ModelRequest$request$1$2.onFailure(ModelRequest.kt:59)
           at com.google.firebase.perf.network.zzf.onFailure(com.google.firebase:firebase-perf@@18.0.1:18)
           at okhttp3.RealCall$AsyncCall.execute(RealCall.java:161)
           at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
           at java.lang.Thread.run(Thread.java:764)
    
    opened by jacksoncheek 2
  • add remove a single subscriber

    add remove a single subscriber

    There was no method to remove a single subscriber.

    Subscribe will return a subscriber which can then be used to call removeSubscriber by the Observable.

    https://compass-tech.atlassian.net/browse/MOBILE-4799

    opened by vincentvvv 2
  • Setup Jitpack

    Setup Jitpack

    Setting up jitpack followed these steps: https://github.com/jitpack/jitpack.io/blob/master/ANDROID.md

    • Creating a release should put this project up on jitpack
    opened by gray419 1
  • Fix for Kotlin Reflection Exception in Observable

    Fix for Kotlin Reflection Exception in Observable

    Summary

    • Fixes crashing bug due to a Kotlin reflection issue in Observable.kt by removing an Android Log.e(...) call, which shouldn't have been in the library to begin with.
    • Removes an unused import in LifecycleTests.kt.

    Root Cause

    • The Android Log.e(...) statement called the Subscriber<E>'s .toString() method, which tried to parse the anonymous lambdas as Strings.

    Solution

    • Remove that call.
    • I would add a unit test for this, but since the Log.e(...) call is getting removed, it doesn't make sense to test that.
    • I'll add the steps to reproduce the error below though.

    How to Reproduce

    • Add the Kotlin reflection artifact and add this test. The stacktrace below will be reproduced.
    class ReflectionErrorTest {
        @Test 
        fun `expect an KotlinReflectionInternalError exception`() {
            var x = 0
    
            fun countUp() {
                x++
            }
    
            println(::countUp.parameters)
        }
    }
    
    // build.gradle
    dependencies {
        testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
    }
    

    Stacktrace

    kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Introspecting local functions, lambdas, anonymous functions and local variables is not yet fully supported in Kotlin reflection
    
    	at kotlin.reflect.jvm.internal.EmptyContainerForLocal.fail(EmptyContainerForLocal.kt:41)
    	at kotlin.reflect.jvm.internal.EmptyContainerForLocal.getFunctions(EmptyContainerForLocal.kt:37)
    	at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.findFunctionDescriptor(KDeclarationContainerImpl.kt:150)
    	at kotlin.reflect.jvm.internal.KFunctionImpl$descriptor$2.invoke(KFunctionImpl.kt:56)
    	at kotlin.reflect.jvm.internal.KFunctionImpl$descriptor$2.invoke(KFunctionImpl.kt:36)
    	at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:92)
    	at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
    	at kotlin.reflect.jvm.internal.KFunctionImpl.getDescriptor(KFunctionImpl.kt)
    	at kotlin.reflect.jvm.internal.KFunctionImpl.getDescriptor(KFunctionImpl.kt:36)
    	at kotlin.reflect.jvm.internal.KCallableImpl$_parameters$1.invoke(KCallableImpl.kt:39)
    	at kotlin.reflect.jvm.internal.KCallableImpl$_parameters$1.invoke(KCallableImpl.kt:21)
    	at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:92)
    	at kotlin.reflect.jvm.internal.KCallableImpl.getParameters(KCallableImpl.kt:71)
    	at kotlin.jvm.internal.CallableReference.getParameters(CallableReference.java:117)
    	at com.compass.snail.ExceptionTests.testSafeNotifyCrash(ExceptionTests.kt:17)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    
    opened by jacksoncheek 0
  • upgrade kotlin to 1.3

    upgrade kotlin to 1.3

    Upgrade Build Tool https://stackoverflow.com/questions/44644524/kotlin-version-that-is-used-for-building-with-gradle-1-1-2-5-differs-from-the

    Warning in gradle - no fix https://stackoverflow.com/questions/52470044/warning-api-variant-getjavacompile-is-obsolete-and-has-been-replaced-with

    Removing Common Pool https://github.com/Kotlin/kotlinx.coroutines/issues/351

    newSingleThread Deprecation https://github.com/Kotlin/kotlinx.coroutines/issues/261

    opened by russellbstephens 0
  • Add map and merge operators (WIP)

    Add map and merge operators (WIP)

    WIP - No tests added yet

    Summary

    • Add map operator (http://reactivex.io/documentation/operators/map.html)
    • Add merge operator (http://reactivex.io/documentation/operators/merge.html)
    opened by jacksoncheek 1
Releases(0.1.2)
Owner
Compass
Compass Real Estate
Compass
Android MVVM framework write in kotlin, develop Android has never been so fun.

KBinding 中文版 Android MVVM framework write in kotlin, base on anko, simple but powerful. It depends on my another project AutoAdapter(A library for sim

Benny 413 Dec 5, 2022
A framework for writing composable parsers based on Kotlin Coroutines.

Parsus A framework for writing composable parsers based on Kotlin Coroutines. val booleanGrammar = object : Grammar<BooleanExpression>() { val ws

Aleksei Semin 28 Nov 1, 2022
Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing functionality and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.), inspired by Badoos RIBs fork of the Uber RIBs framework

Decompose Please see the project website for documentation and APIs. Decompose is a Kotlin Multiplatform library for breaking down your code into life

Arkadii Ivanov 819 Dec 29, 2022
Kotlin Multiplatform Mobile + Mobile Declarative UI Framework (Jetpack Compose and SwiftUI)

Kotlin Multiplatform Mobile + Mobile Declarative UI Framework (Jetpack Compose and SwiftUI)

Kotchaphan Muangsan 3 Nov 15, 2022
Framework for quickly creating connected applications in Kotlin with minimal effort

Ktor is an asynchronous framework for creating microservices, web applications and more. Written in Kotlin from the ground up. import io.ktor.server.n

ktor.io 10.7k Jan 9, 2023
A modular object storage framework for Kotlin multiplatform projects.

ObjectStore A modular object storage framework for Kotlin multiplatform projects. Usage ObjectStore provides a simple key/value storage interface whic

Drew Carlson 4 Nov 10, 2022
This is powerful android framework

FlairFramework This is an android framework for build complex application with different architectures (MVC ready/MVP/MVVM/MVI ets). It's create on to

Alexandr Minkin 31 Nov 29, 2021
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

Cossack Labs 1.6k Jan 8, 2023
General purpose parsing framework. Simplify parsing of text

General purpose parsing framework. Simplify parsing of text. Allows capture complex nested formats with simple and human-readable syntax.

Roman 1 Nov 16, 2021
Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Vehement 8 Nov 26, 2022
Ivy FRP is a Functional Reactive Programming framework for declarative-style programming for Android

FRP (Functional Reactive Programming) framework for declarative-style programming for Andorid. :rocket: (compatible with Jetpack Compose)

null 8 Nov 24, 2022
A sample application that build with combine use Clean Architecture framework and Github API

The Github Example Introduction This is a sample application that build with combine use Clean Architecture framework and Github API (https://develope

Nguyễn Hùng An 2 Aug 12, 2022
Run Kotlin/JS libraries in Kotlin/JVM and Kotlin/Native programs

Zipline This library streamlines using Kotlin/JS libraries from Kotlin/JVM and Kotlin/Native programs. It makes it possible to do continuous deploymen

Cash App 1.5k Dec 30, 2022
A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

common sense OSS 0 Jan 20, 2022
Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in Kotlin with Jetpack Compose and a backed in Kotlin hosted on AppEngine.

Conferences4Hall Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in K

Gérard Paligot 98 Dec 15, 2022
Android + Kotlin + Github Actions + ktlint + Detekt + Gradle Kotlin DSL + buildSrc = ❤️

kotlin-android-template ?? A simple Github template that lets you create an Android/Kotlin project and be up and running in a few seconds. This templa

Nicola Corti 1.5k Jan 3, 2023
LifecycleMvp 1.2 0.0 Kotlin is MVP architecture implementation with Android Architecture Components and Kotlin language features

MinSDK 14+ Download Gradle Add to project level build.gradle allprojects { repositories { ... maven { url 'https://jitpack.io' }

Robert 20 Nov 9, 2021
Opinionated Redux-like implementation backed by Kotlin Coroutines and Kotlin Multiplatform Mobile

CoRed CoRed is Redux-like implementation that maintains the benefits of Redux's core idea without the boilerplate. No more action types, action creato

Kittinun Vantasin 28 Dec 10, 2022
👋 A common toolkit (utils) ⚒️ built to help you further reduce Kotlin boilerplate code and improve development efficiency. Do you think 'kotlin-stdlib' or 'android-ktx' is not sweet enough? You need this! 🍭

Toolkit [ ?? Work in progress ⛏ ?? ??️ ?? ] Snapshot version: repositories { maven("https://s01.oss.sonatype.org/content/repositories/snapshots") }

凛 35 Jul 23, 2022