Skip to content

Releases: RedMadRobot/mapmemory

v2.1

06 May 05:59
714ed91
Compare
Choose a tag to compare

Reusable properties

Reusable properties introduced to address the problem described in issue #14

Reusable properties survive MapMemory.clear() call. It will not be removed from cache, but will be cleared instead. Reusable properties are especially useful for reactive types like Flow. You don't need to resubscribe to flow after MapMemory was cleared.

val flow by memory.sharedFlow<Int>()

// Subscribe to flow
flow.onEach(::println).launchIn(coroutineScope)
// And then clear MapMemory
memory.crear()

// Emitted value will be printed because the flow
// is the same as before memory clear
flow.emit(1)

You can create reusable property using operator invoke with clear lambda:

class Counter {
    fun reset() = { /*...*/ }
}

val counter: Counter by memory(clear = { it.reset() }) { Counter() }

Many of default accessors are already turned into reusable: mutableList, mutableMap, reactiveMutableMap, stateFlow, sharedFlow, behaviorSubject, publishSubject.

Changes

  • ⚠️ Deprecated functions removed: MapMemory.nullable, MapMemory.reactiveMap, ReactiveMutableMap.getStream, ReactiveMutableMap.getAll, ReactiveMutableMap.getAllStream
  • Added parameter defaultValue to most of reusable properties: mutableList, mutableMap, reactiveMutableMap, behaviorSubject.
  • ⚠️ mapmemory-rxjava: ReplayStrategy was removed. Please let us know if this change affected you: #20

Fixes

  • ReactiveMutableMap: initial empty map is not emitted (#15)

Dependencies

  • mapmemory: Kotlin 1.4.301.8.20
  • mapmemory-coroutines: kotlinx.coroutines 1.4.21.6.4
  • mapmemory-rxjava3: RxJava 3.0.113.1.6

Housekeeping

  • infrastructure 0.8.20.18.1
  • detekt 1.16.01.22.0
  • Gradle 6.8.38.1.1
  • binary-compatibility-validator 0.5.00.13.1

Full Changelog: v2.0...v2.1

v2.0

01 May 20:17
7101df3
Compare
Choose a tag to compare

ReactiveMap refactored

ReactiveMap renamed to ReactiveMutableMap.
There are two type parameters K (for keys), V (for values) instead of one T (for values), so you can use keys with a type different from String.

Now ReactiveMutableMap implements interface MutableMap.
Also, you can wrap Map with ReactiveMutableMap, using constructor.

Naming changes

Old versions of methods are marked with @Deprecated to help migrate to new naming.

Methods getAll replaced with field values to match Map interface.

Word stream in methods names replaced with implementation-specific words to make API clearer.

Coroutines:

  • getStreamgetFlow and getValueFlow
  • getAllStreamvaluesFlow
  • New field flow with the whole map

RxJava:

  • getStreamgetValueObservable
  • getAllStreamvaluesObservable
  • New field observable with the whole map

KAPT: 'IllegalStateException: Couldn't find declaration file' on delegate with inline getValue operator

There is a bug in Kotlin Compiler that affects MapMemory if you create subclasses - KT-46317.
You can use module mapmemory-kapt-bug-workaround as a workaround:

dependencies {
    implementation("com.redmadrobot.mapmemory:mapmemory-kapt-bug-workaround:[latest-version]")
}
- val someValue: String by memory
+ val someValue: String by memory.value()

v2.0-rc1

14 Mar 13:06
6047eda
Compare
Choose a tag to compare

Scoped and shared values (#1)

Now there are two types of memory values: scoped (to class) and shared.

All memory values by default are scoped to the class where it's declared.
Scoping prevents from unintended sharing of properties with the same name between classes.
This snippet demonstrates the problem:

package com.example

class StringsStorage(memory: MapMemory) {
    var values: MutableList<String> by memory.list()
}

class IntsStorage(memory: MapMemory) {
    var values: MutableList<Int> by memory.list() // The same field name as in StringsStorage
}

val strings = StringsStorage(memory)
val ints = IntsStorage(memory)

strings.values.add("A")
ints.values.add(1)

println(memory) 

Output:

For unscoped fields (old behaviour):
{values: [A, 1]}

For scoped fields (new behavior):
{com.example.StringsStorage#values: [A], com.example.IntsStorage#values: [1]}

You can make memory field shared using extension shared(key: String):

// It is recommended to create constants for shared properties keys
const val KEY_SERVER_HOST = "serverHost"

class ServerConfig(memory: MapMemory) {
    var host: String by memory.shared(KEY_SERVER_HOST)
}

class DebugPanelConfig(memory: MapMemory) {
    var serverHost: String by memory.shared(KEY_SERVER_HOST)
}

Removed .nullable() and .withDefault { ... }

Accessor nullable() is not needed now.
You can just declare a nullable field:

-val selectedOption: String? by memory.nullable()
+val selectedOption: String? by memory

withDefault is no more compatible with MapMemory, so you should use the operator invoke instead:

-var counter: Int by memory.withDefault { 0 }
+var counter: Int by memory { 0 }

Mutable collections accessors

BREAKING CHANGE

Now accessors map and list return delegates to access immutable collections.
You should use mutableMap and mutableList for mutable versions of collections.

Added

  • Copying constructor for MapMemory.
    Now you can initialize memory with specified content on creation.
  • New module mapmemory-test.
    Contains utilities helping to test code that uses MapMemory.
  • New module mapmemory-rxjava3 with accessors for RxJava3.

Changed

  • MapMemory now is MutableMap<String, Any> instead of MutableMap<String, Any?>.
    It is made to prevent NPEs because ConcurrentHashMap not supports nullable values.
    You still can store nullable values in memory using a delegate.

v1.1

25 Feb 22:15
059a455
Compare
Choose a tag to compare

Added

  • Method ReactiveMap.getValue (#2)

Changed

  • ReactiveMap constructor now is public (#4)

Housekeeping

  • Updated Kotlin to 1.4.30
  • Updated Gradle to 6.8
  • Updated Detekt to 1.15.0
  • Migrated from JCenter to Maven Central (#5)

v1.0

05 Nov 10:56
417b474
Compare
Choose a tag to compare

First release!