项目作者: etiennelenhart

项目描述 :
Redux-inspired Android architecture library leveraging Architecture Components and Kotlin Coroutines
高级语言: Kotlin
项目地址: git://github.com/etiennelenhart/Eiffel.git
创建时间: 2017-12-08T14:59:13Z
项目社区:https://github.com/etiennelenhart/Eiffel

开源协议:MIT License

下载


Eiffel

Build Status
JitPack

Logo

A Redux-inspired Android architecture library leveraging Architecture Components and Kotlin Coroutines.

Quick example

  1. data class HelloEiffelState(val greeting: String = "Hello Eiffel") : State
  2. sealed class HelloEiffelAction : Action {
  3. object NowInFrench : HelloEiffelAction()
  4. data class Greet(val name: String) : HelloEiffelAction()
  5. }
  6. val helloEiffelUpdate = update<HelloEiffelState, HelloEiffelAction> { action ->
  7. when (action) {
  8. is HelloEiffelAction.NowInFrench -> copy(greeting = greeting.replace("Hello", "Salut"))
  9. is HelloEiffelAction.Greet -> copy(greeting = "Salut ${action.name}")
  10. }
  11. }
  12. class HelloEiffelViewModel(initialState: HelloEiffelState) :
  13. EiffelViewModel<HelloEiffelState, HelloEiffelAction>(initialState) {
  14. override val update = helloEiffelUpdate
  15. }
  16. class HelloEiffelFragment : Fragment() {
  17. private val viewModel: HelloEiffelViewModel by eiffelViewModel()
  18. ...
  19. override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
  20. // example with View Bindings
  21. binding = FragmentHelloEiffelBinding.inflate(inflater, container, false)
  22. viewModel.state.observe(viewLifecycleOwner) { state ->
  23. binding.greetingText.text = state.greeting
  24. }
  25. binding.frenchButton.setOnClickListener { viewModel.dispatch(HelloEiffelAction.NowInFrench) }
  26. return binding.root
  27. }
  28. ...
  29. }

Installation

build.gradle (project)

  1. repositories {
  2. maven { url 'https://jitpack.io' }
  3. }

build.gradle (module)

  1. dependencies {
  2. implementation 'com.github.etiennelenhart.eiffel:eiffel:5.0.0'
  3. implementation 'com.github.etiennelenhart.eiffel:eiffel-test:5.0.0'
  4. }

Features

Apart from providing Redux-like reactive ViewModels, Eiffel includes the following features to simplify common Android-related tasks and architecture plumbing:

  • First class support for Kotlin Coroutines and Flow
  • Powerful middleware functionality in the form of Interceptions with an easy-to-use DSL
  • Extended state observing for subscribing to specific state properties only
  • Convenient way to restore part or all of a state after process death
  • BindableState class to adapt one or more states for use with Data Binding
  • Simple option to pass Intent extras and Fragment arguments to a ViewModel’s initial state
  • Implementation of a ViewEvent for one-off events inside of states
  • Resource wrapper to associate a status to LiveData
  • Delegated properties to lazily access a ViewModel indside an Activity or Fragment
  • A dedicated debug mode to trace all dispatched actions, interception calls and state updates
  • Separate testing module with JUnit rules to test async behavior and helpers to test a chain of Interceptions in isolation

Info on all of these and more can be found in the Wiki.

Interceptions DSL

Eiffel includes an easy-to-use Domain-specific language for creating a chain of Interceptions. This allows you to define the logic of your ViewModel domain in a simple and declarative way. Iterating on the quick example above, this is how you can define a set of interceptions in a few lines of code:

  1. val helloEiffelInterceptions = interceptions<HelloEiffelState, HelloEiffelAction> {
  2. add(CustomInterception()) // your custom interception
  3. pipe { _, action -> Analytics.log("HelloEiffel", action) } // log something to analytics
  4. on<HelloEiffelAction.Greet> { // following will only react to 'Greet' action
  5. adapter("Upper case name") { _, action ->
  6. HelloEiffelAction.Greet(action.name.toUpperCase())
  7. }
  8. filter { state, action -> // ignore duplicate button presses and empty names
  9. !state.greeting.contains(action.name) || action.name.isNotBlank()
  10. }
  11. }
  12. }
  13. class HelloEiffelViewModel(initialState: HelloEiffelState) :
  14. EiffelViewModel<HelloEiffelState, HelloEiffelAction>(initialState) {
  15. override val update = helloEiffelUpdate
  16. override val interceptions = helloEiffelInterceptions
  17. }

Migration

Migration guides for breaking changes: