{"id":19847072,"url":"https://github.com/polidea/state-machine-android","last_synced_at":"2025-05-01T21:31:55.915Z","repository":{"id":34767196,"uuid":"38749187","full_name":"Polidea/state-machine-android","owner":"Polidea","description":"A lightweight state machine implementation for Android.","archived":false,"fork":false,"pushed_at":"2015-07-08T12:48:38.000Z","size":224,"stargazers_count":24,"open_issues_count":2,"forks_count":5,"subscribers_count":14,"default_branch":"master","last_synced_at":"2023-04-01T06:23:05.342Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"stekylsha/cisc190-projects","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Polidea.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2015-07-08T11:08:07.000Z","updated_at":"2023-04-01T06:23:05.358Z","dependencies_parsed_at":"2022-09-11T12:02:20.065Z","dependency_job_id":null,"html_url":"https://github.com/Polidea/state-machine-android","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fstate-machine-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fstate-machine-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fstate-machine-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fstate-machine-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Polidea","download_url":"https://codeload.github.com/Polidea/state-machine-android/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224278376,"owners_count":17285080,"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-12T13:13:21.199Z","updated_at":"2024-11-12T13:13:21.966Z","avatar_url":"https://github.com/Polidea.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# State Machine for Android\n\nA lightweight state machine implementation for Android.\n\n## Download\n\nVia gradle. In main build.gradle :\n\n```gradle\nallprojects {\n    repositories {\n        ...\n        maven {\n            url \"https://oss.sonatype.org/content/repositories/snapshots\"\n        }\n    }\n}\n```\n\nAdd library:\n\n```gradle\ncompile 'com.polidea:statemachine:1.0.0-SNAPSHOT'\n```\n\nor Maven. Add plugin repository:\n\n```xml\n\u003cpluginRepository\u003e\n    \u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots/\u003c/url\u003e\n    \u003csnapshots\u003e\n        \u003cenabled\u003etrue\u003c/enabled\u003e\n    \u003c/snapshots\u003e\n\u003c/pluginRepository\u003e\n```\n\nAdd library:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.polidea\u003c/groupId\u003e\n  \u003cartifactId\u003estatemachine\u003c/artifactId\u003e\n  \u003cversion\u003e1.0.0-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n**It is a stable version of library**\n\n## Usage\n\n### Creating custom BaseStateableHandler\n\nThe easiest way to use StateMachine is to extend `BaseStateableHandler`. It have 4 main methods that we should override:\n\n* `getStateProvider()` - used by State's to get data from our Fragment/Activity. Base StateProvider contains one method `provideContext()`\n* `getActionInterface()` - used by State's to perform action's on Activity/Fragment, e.g. show Toast.\n* `getInitialStateClass()` - initial state class for `StateMachine`. By default it returns `InitialState` class.\n* `onStateMachineDescribe(StateMachine stateMachine)` - here we should describe transitions between states in our `StateMachine`. Each transition is a set of: from class, to class, event id. It means: when current state is 'from state' and it will propagate 'event id' then state machine should go to 'to state'.\n\nSample `BaseStateableHandler`:\n\n```java\npublic class LoginStateableHandler extends BaseStateableHandler\u003cLoginProvider, LoginActionInterface\u003e implements LoginProvider, LoginActionInterface {\n    @Override\n    public LoginProvider getStateProvider() {\n        return this;\n    }\n\n    @Override\n    public LoginActionInterface getActionInterface() {\n        return this;\n    }\n\n    @Override\n    public int provideFragmentContainerId() {\n        return R.id.fragment_container;\n    }\n\n    @Override\n    public void onStateMachineDescribe(StateMachine\u003cLoginProvider, LoginActionInterface\u003e stateMachine) {\n        stateMachine.addTransitionFromClass(LoginInitialState.class, LoginEvents.START_LOGIN, OnGoingLoginState.class);\n\n        stateMachine.addTransitionFromClass(OnGoingLoginState.class, LoginEvents.CANCELLED, LoginInitialState.class);\n        stateMachine.addTransitionFromClass(OnGoingLoginState.class, LoginEvents.SENDING_IN_PROGRESS, WaitingForLoginRequestState.class);\n\n        stateMachine.addTransitionFromClass(WaitingForLoginRequestState.class, LoginEvents.FINISHED, InitialState.class);\n    }\n\n    @Override\n    public Class\u003c? extends State\u003e getInitialStateClass() {\n        return LoginInitialState.class;\n    }\n\n    ...\n}\n```\n\nAs you can see here, state machine contains 3 states: `LoginInitialState`, `OnGoingLoginState` and `WaitingForLoginRequestState`. Initial state is `LoginInitialState`. Looking at one of transition:\n\n```java\nstateMachine.addTransitionFromClass(LoginInitialState.class, LoginEvents.START_LOGIN, OnGoingLoginState.class);\n```\n\nmeans that, when state machine is in `LoginInitialState` and that state will fire `LoginEvents.START_LOGIN` event, then state machine should go to state `OnGoingLoginState`.\n\n### Starting custom BaseStateableHandler\n\nTo make `LoginStateableHandler` work, you must remember to call it's `onCreate(Bundle savedInstanceState)`, `onResume()`, `onPause()`, `onSaveInstanceState(Bundle outState)` methods in appropriate Fragment/Activity lifecycle method's. Sample usage:\n\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    ...\n    handler = new LoginStateableHandler();\n    handler.onCreate(savedInstanceState);\n}\n\n@Override\nprotected void onResume() {\n    super.onResume();\n    handler.onResume();\n}\n\n@Override\nprotected void onPause() {\n    super.onPause();\n    handler.onPause();\n}\n\n@Override\nprotected void onSaveInstanceState(Bundle outState) {\n    super.onSaveInstanceState(outState);\n    handler.onSaveInstanceState(outState);\n}\n```\n\nOf course you can initialize handler from other places, not only Fragment/Activity. Here is an example of starting handler in singleton class like `Application`:\n\n```java\npublic class MyApplication extends Application {\n\n    LoginStateableHandler handler;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        handler = new LoginStateableHandler();\n        handler.onCreate(null);\n        handler.onResume();\n    }\n}\n```\n\n### Creating states\n\nState machine consist of states. Each state should extends `State` that contains two methods:\n\n* `onStateApplied()` - called when entering state\n* `onStateLeft()` - called when leaving state\n\nEach state should call `fireEvent(int eventId)` when it finish it's job. Sample `State`:\n\n```java\npublic class OnGoingLoginState extends State\u003cLoginProvider, LoginActionInterface\u003e{\n\n    @Inject\n    Bus bus;\n\n    @Inject\n    NetworkManager networkManager;\n\n    public OnGoingLoginState() {\n        Application.getComponentInstance().inject(this);\n    }\n\n    @Override\n    public void onStateApplied() {\n        bus.register(this);\n    }\n\n    @Override\n    public void onStateLeft() {\n        bus.unregister(this);\n    }\n\n    @Subscribe\n    public void onBusLoginEvent(BusLoginEvent loginEvent) {\n        networkManager.loginUser(loginEvent.getEmail(), loginEvent.getPassword());\n        fireEvent(LoginEvents.SENDING_IN_PROGRESS);\n    }\n}\n```\n\nIt is nice to use some Bus implementation, like [EventBus](https://github.com/greenrobot/EventBus) or [Otto](https://github.com/square/otto), to receive applications events.\u003cp/\u003e\nIn that example we use [Otto](https://github.com/square/otto) for sending `BusLoginEvent` (it may be send by activity when 'Login' button tapped) and receiving that event in `OnGoingLoginState`.\n\n## Used libraries\n\n* **[otto]** https://github.com/square/otto\n* **[dagger 2]** https://github.com/google/dagger\n* **[spock]** https://code.google.com/p/spock/\n* **[android support library v7]**\n\n## LICENSE\n\n[LICENSE](./LICENSE)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolidea%2Fstate-machine-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolidea%2Fstate-machine-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolidea%2Fstate-machine-android/lists"}