Grimoire Transfusion

The Grimoire's transfusion spell allows you to channel your resources unidirectionally

License

License

GroupId

GroupId

com.skoumal.grimoire
ArtifactId

ArtifactId

transfusion-environment
Last Version

Last Version

1.1.0-alpha01
Release Date

Release Date

Type

Type

aar
Description

Description

Grimoire Transfusion
The Grimoire's transfusion spell allows you to channel your resources unidirectionally
Project URL

Project URL

https://github.com/skoumalcz/grimoire-transfusion
Source Code Management

Source Code Management

https://github.com/skoumalcz/grimoire-transfusion

Download transfusion-environment

How to add to project

<!-- https://jarcasting.com/artifacts/com.skoumal.grimoire/transfusion-environment/ -->
<dependency>
    <groupId>com.skoumal.grimoire</groupId>
    <artifactId>transfusion-environment</artifactId>
    <version>1.1.0-alpha01</version>
    <type>aar</type>
</dependency>
// https://jarcasting.com/artifacts/com.skoumal.grimoire/transfusion-environment/
implementation 'com.skoumal.grimoire:transfusion-environment:1.1.0-alpha01'
// https://jarcasting.com/artifacts/com.skoumal.grimoire/transfusion-environment/
implementation ("com.skoumal.grimoire:transfusion-environment:1.1.0-alpha01")
'com.skoumal.grimoire:transfusion-environment:aar:1.1.0-alpha01'
<dependency org="com.skoumal.grimoire" name="transfusion-environment" rev="1.1.0-alpha01">
  <artifact name="transfusion-environment" type="aar" />
</dependency>
@Grapes(
@Grab(group='com.skoumal.grimoire', module='transfusion-environment', version='1.1.0-alpha01')
)
libraryDependencies += "com.skoumal.grimoire" % "transfusion-environment" % "1.1.0-alpha01"
[com.skoumal.grimoire/transfusion-environment "1.1.0-alpha01"]

Dependencies

compile (3)

Group / Artifact Type Version
androidx.databinding » databinding-common jar 4.1.1
androidx.databinding » databinding-runtime jar 4.1.1
androidx.databinding » databinding-adapters jar 4.1.1

runtime (3)

Group / Artifact Type Version
org.jetbrains.kotlin : kotlin-stdlib jar 1.4.20
org.jetbrains.kotlin : kotlin-reflect jar 1.4.20
org.jetbrains.kotlinx : kotlinx-coroutines-android jar 1.4.1

Project Modules

There are no modules declared in this project.

GrimoireTransfusion

Why Transfusion?

  • :)

    Well you need some parts of your app to talk to each other.

Observer

Observer works as a drop-in utility to bindable objects. The main benefit is that you don't need to use heavy ObservableFields which collect listeners within them - often overlapping with other ObservableFields.

With observer you're able to use native kotlin delegation for pretty syntax and improved performance.

class MyBindableObject : Observer by Observer.getDefault() {

    @get:Bindable
    var myVariable by observable(Any(), BR.myVariable)
        private set

    fun onStateChanged() {
        // todo mutate myVariable
    }

}

Transfusion + extensions

Transfusion offers unidirectional communication within a specific scope of items provided. One object always serves as provider, other as consumer. Default implementation allows multiple consumers, however you should be aware that this can bring undesired consequences.

data class MyState(
    val isExpanded: Boolean = false
)

class MyViewModel : ViewModel(), Transfusion<MyState> by Transfusion.getDefault() {

    private var state = MyState()

    fun onExpand() {
        state = state.copy(isExpanded = true)
        state.offer()
    }

}

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModels()

    override fun onViewCreated(/**/) {
        lifecycleScope.launch {
            viewModel.openFlow().collect { /* it: MyState -> */ }
        }
    }

}

What's shown above is a very raw example. However that's not the way you're gonna be using transfusion since we provide extensions Here's how to use them.

class MyViewModel : ViewModel(), Transfusion<Cell> by Transfusion.getDefault() {

    fun onExpand() = MyFragment.Expand().offer()

}

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModels()
    private lateinit var consumer: TransfusionFlowConsumer<Cell>

    override fun onViewCreated(/**/) {
        consumer = viewModel.openFlow().consumeIn(this)
    }

    override fun onDestroyView() {
        consumer.stop()
    }

    private fun doExpand() {}

    class Expand : Cell(), InFragment {
        override fun invoke(fragment: Fragment) {
            if(fragment !is MyFragment) return
            fragment.doExpand()
        }
    }

}

Notice that by using this pattern of having Cell classes inside the Fragment, we are able to use private methods. This is very much beneficial for keeping consumers of MyFragment accidentally calling public method that's not supposed to be called directly.

Also you can use InActivity, InContext, InFragment. Consult the documentation for each interface to learn the caveats of using each of them.

LiveTransfusionHost

You might be consuming LiveData outside lifecycle and accidentally leaking precious resources. Then the easy way out is to use LiveTransfusionHost. It gets implemented just as easy as the rest of the utilities mentioned here and is just as powerful.

class MyViewModel : ViewModel(), LiveTransfusionHost by LiveTransfusionHost.getDefault() {

    private val databaseWindow: LiveData<List<String>> = getFromSomewhere()

    init {
        databaseWindow.transfusion { /* it: List<String> -> */ }
    }

    override fun onCleared() {
        clearTransfusions()
    }

}

Logo by smalllikeart

com.skoumal.grimoire

SKOUMAL

Versions

Version
1.1.0-alpha01