{"id":19260640,"url":"https://github.com/evant/redux","last_synced_at":"2025-07-13T00:40:43.062Z","repository":{"id":57736729,"uuid":"70371145","full_name":"evant/redux","owner":"evant","description":"Redux ported to java/android (name tbd)","archived":false,"fork":false,"pushed_at":"2020-06-14T22:51:10.000Z","size":1352,"stargazers_count":191,"open_issues_count":4,"forks_count":24,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-04-13T08:21:51.363Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evant.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-09T02:36:55.000Z","updated_at":"2024-06-28T23:25:35.000Z","dependencies_parsed_at":"2022-08-24T14:57:22.809Z","dependency_job_id":null,"html_url":"https://github.com/evant/redux","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/evant/redux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fredux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fredux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fredux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fredux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evant","download_url":"https://codeload.github.com/evant/redux/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fredux/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265076119,"owners_count":23707513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T19:22:13.758Z","updated_at":"2025-07-13T00:40:42.991Z","avatar_url":"https://github.com/evant.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# redux for java/android (name tbd)\nRedux ported to java/android\n\nI've seen a few of these floating around, but this one has some specific benefits over other\nimplementations.\n* Any object can be used as an action or state.\n* Built-in functions to help compose reducers\n* Middleware that's actually implemented like you'd expect.\n* Thunk and rxjava dispatchers.\n* A fully-fleshed-out android sample.\n\n## Download\n[![Maven Central](https://img.shields.io/maven-central/v/me.tatarka.redux/redux-core.svg)](https://search.maven.org/search?q=g:me.tatarka.redux)\n[![Sonatype Snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/me.tatarka.redux/redux-core.svg)](https://oss.sonatype.org/content/repositories/snapshots/me/tatarka/redux/)\n\n```groovy\nrepositories {\n  mavenCentral()\n}\n\ndependencies {\n  compile \"me.tatarka.redux:redux-core:0.11\"\n  compile \"me.tatarka.redux:redux-android:0.11\"\n  compile \"me.tatarka.redux:redux-android-lifecycle:0.11\"\n  compile \"me.tatarka.redux:redux-thunk:0.11\"\n  compile \"me.tatarka.redux:redux-rx:0.11\"\n  compile \"me.tatarka.redux:redux-rx2:0.11\"\n}\n```\n\n## Usage\n\nCreate a store.\n```java\nSimpleStore\u003cState\u003e store = new SimpleStore(initialState);\n```\n\nGet the current state.\n```java\nState state = store.state();\n```\n\nListen to state changes.\n```java\nstore.addListener(new Listener\u003cState\u003e() {\n  @Override\n  public void onNewState(State state) {\n    ...\n  }\n});\n```\n\nOr with rxjava (using redux-rx).\n```java\nObservableAdapter.observable(store).subscribe(state -\u003e { ... });\n```\n\nOr with rxjava2 (using redux-rx2).\n```java\nFlowableAdapter.flowable(store).subscribe(state -\u003e { ... });\n```\n\nCreate a dispatcher with optional middleware.\n```java\nDispatcher\u003cAction, Action\u003e dispatcher = Dispatcher.forStore(store, reducer)\n    .chain(middleware...);\n```\n\nDispatch actions.\n```java\ndispatcher.dispatch(new MyAction());\n```\n\n## Android\n\nYou can observe your store with `LiveData` which will properly tie into the android lifecycle.\n```java\nLiveDataAdapter.liveData(store).observe(this, state -\u003e { ... });\n```\n\nYou can use `StoreViewModel` to keep your store around for the lifetime of an activity/fragment\nsurviving configuration changes.\n```java\npublic class MyViewModel extends StoreViewModel\u003cState, MyViewModel\u003e {\n  public MyViewModel() {\n    super(new MyStore());\n  }\n}\n```\n\n```java\npublic class MyActivity extends LifecycleActivity {\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);\n    MyStore store = viewModel.getStore();\n    viewModel.getState().observe(this, state -\u003e { ... });\n  }\n}\n```\n\nSince `LiveData` relays state changes to the main thread, you may lose important stack trace info.\nYou can get it back by calling `LiveDataAdapter.liveData(store, true)` or\n`LiveDataAdapter.setDebugAll(true)`. This creates an expensive stacktrace on every dispatch so you\nprobably don't want it on release. A common pattern would be to put\n`LiveDataAdapter.setDebugAll(BuildConfig.DEBUG)` in your setup code.\n\n## Composing Reducers\n\nIt's common you'd want to switch on actions values or class type. `Reducers.matchValue()` and\n`Reducers.matchClass()` makes this easy.\n```java\nReducer\u003cString, State\u003e reducer = Reducers.matchValue()\n  .when(\"action1\", new Action1Reducer())\n  .when(\"action2\", new Action2Reducer());\n\nReducer\u003cObject, State\u003e reducer = Reducers.matchClass()\n  .when(Action1.class, new Action1Reducer())\n  .when(Action2.class, new Action2Reducer());\n```\n\nThere is also `Reducers.match()` which takes a predicate for more complicated matching setups.\n```java\nReducer\u003cObject, State\u003e reducer = Reducers.match()\n  .when(Predicates.is(\"action1\"), new Action1Reducer())\n  .when(Predicates.instanceOf(Action2.class), new Action2Reducer());\n```\n\nYou can also run a sequence of reducers with `Reducers.all(reducer1, reducer2, ...)` or run reducers\nuntil one changes the state with `Reducers.first(reducer1, reducer2, ...)`.\n\n## Thunk Dispatcher\n\nAllows you to dispatch async functions as actions.\n\n```java\nSimpleStore\u003cState\u003e store = new SimpleStore\u003c\u003e(initialState);\nThunkDispatcher\u003cAction, Action\u003e dispatcher = new ThunkDispatcher\u003c\u003e(Dispatcher.forStore(store, reducer));\n\ndispatcher.dispatch(new Thunk\u003cAction, Action\u003e() {\n  @Override\n  public void run(Dispatcher\u003cAction, Action\u003e dispatcher) {\n    dispatcher.dispatch(new StartLoading());\n    someAsyncCall(new Runnable() {\n      @Override\n      public void run() {\n        dispatcher.dispatch(new StopLoading());\n      }\n    }\n  }\n});\n```\n\n## Observable Dispatcher\n\nAlternatively, you can use the `ObservableDispatcher` to dispatch a stream of actions.\n\n```java\nSimpleStore\u003cState\u003e store = new SimpleStore\u003c\u003e(initialState);\nObservableDispatcher\u003cAction\u003e dispatcher = new ObservableDispatcher\u003c\u003e(Dispatcher.forStore(store, reducer));\n\ndispatcher.dispatch(callThatReturnsObservable()\n    .map(result -\u003e new StopLoading())\n    .startWith(Observable.just(new StartLoading())));\n```\n\n## Subclassing a Store\n\nDon't want to have to worry about passing around the store and dispatchers? You can subclass\n`SimpleStore` and create your own dispatch methods. This also simplifies generics a bit when using\nthroughout your app.\n\n```java\npublic class MyStore extends SimpleStore\u003cState\u003e {\n\n  private final Dispatcher\u003cAction, Action\u003e dispatcher;\n  private final ObservableDispatcher\u003cAction\u003e observableDispatcher;\n\n  public MyStore() {\n    super(new State());\n    dispatcher = Dispatcher.forStore(this, new MyReducer())\n      .chain(new LogMiddleware\u003c\u003e(\"ACTION\"));\n    observableDispatcher = new ObservableDispatcher\u003c\u003e(dispatcher);\n  }\n\n  public Action dispatch(Action action) {\n    return dispatcher.dispatch(action);\n  }\n\n  public Subscription dispatch(Observable\u003cAction\u003e actions) {\n    return observableDispatcher.dispatch(actions);\n  }\n\n  public Observable\u003cAction\u003e observable() {\n    return ObservableAdapter.observable(this);\n  }\n}\n```\n\nNow you can just pass the single store around and call `store.dispatch()`.\n\n## Debug Utilities\n\n### Android LogMiddleware\n\nYou can log all actions on android with the built-in `LogMiddleware`.\n\n```java\ndispatcher = Dispatcher.forStore(store, reducer)\n  .chain(new LogMiddleware\u003cAction, Action\u003e(\"ACTION\"));\n```\n\n### ReplayMiddleware\n\nYou can disable/enable actions and see how that effects your ui with the replay middleware. It will\nreplay your modified actions back on the initial state.\n\n```groovy\ncompile \"me.tatarka.redux:redux-replay:0.10\"\n```\n\n```java\nreplay = new ReplayMiddleware\u003cState, Action, Action\u003e(store, reducer);\ndispatcher = Dispatcher.forStore(store, reducer)\n  .chain(replay);\n\nreplay.actions() // lists all actions that have been dispatched\nreplay.disable(index) // disables action at given index\nreplay.enable(index) // enables action at the given index\n```\n\nThe sample android app includes a debug drawer to let you interact with this middleware.\n\n### Redux Debugging tools integration.\n\nYou can connect to [RemoteDev Server](https://github.com/zalmoxisus/remotedev-server) to interact\nwith various redux debugging UI's. Currently only displaying actions/state is supported.\n\n```\nnpm install -g remotedev-server\nremotedev --hostname=localhost --port=8000\n```\n\n```groovy\ncompile \"me.tatarka.redux:redux-monitor:0.11\"\n```\n\n```java\ndispatcher = Dispatcher.forStore(store, reducer)\n  .chain(new MonitorMiddleware(store));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fredux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevant%2Fredux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fredux/lists"}