{"id":21702256,"url":"https://github.com/huangyanbin/smartflow","last_synced_at":"2025-04-12T14:42:58.227Z","repository":{"id":108876395,"uuid":"237745617","full_name":"huangyanbin/SmartFlow","owner":"huangyanbin","description":"Android streaming response （Android 流式响应）","archived":false,"fork":false,"pushed_at":"2020-02-04T01:43:56.000Z","size":237,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-26T09:21:17.232Z","etag":null,"topics":["android","events","flow","stream-processing"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/huangyanbin.png","metadata":{"files":{"readme":"README-en.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-02-02T09:12:19.000Z","updated_at":"2024-02-21T02:29:24.000Z","dependencies_parsed_at":"2023-04-06T08:35:52.812Z","dependency_job_id":null,"html_url":"https://github.com/huangyanbin/SmartFlow","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangyanbin%2FSmartFlow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangyanbin%2FSmartFlow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangyanbin%2FSmartFlow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangyanbin%2FSmartFlow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/huangyanbin","download_url":"https://codeload.github.com/huangyanbin/SmartFlow/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248583519,"owners_count":21128610,"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":["android","events","flow","stream-processing"],"created_at":"2024-11-25T21:12:58.814Z","updated_at":"2025-04-12T14:42:58.201Z","avatar_url":"https://github.com/huangyanbin.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SmartFlow\nAndroid streaming response \n##### [中文说明](README.md)\n[![](https://www.jitpack.io/v/huangyanbin/SmartFlow.svg)](https://www.jitpack.io/#huangyanbin/SmartFlow)\n### Cause\nIn Android, we often encounter asynchronous method nesting. For example, after submitting a file, submit a form, and then make other logical processing according to whether the data is successful or not. Kotlin puts forward the concept of CO process and uses grammar sugar to solve this problem. There is also async / await in JavaScript to make asynchrony work like synchronization. In Java (before Java 9), there is no such feature, which makes writing asynchronous nesting feel like hell. During the Spring Festival, I tried to alleviate the problem, so I wrote a flow box.\n### Idea\nThinking about code from life, the principle of method nesting and water flow is very similar. We treat each asynchrony as a water pipe, and water flows through each pipe, and each pipe can process and transform water. This process of transformation is regarded as an event. In the wrapper event, we can transform it by thread, event, merge and split. If an exception is encountered, the flow is terminated directly.\n\n### Function\n###### Simple example\nCreate a flow through the flow static create method, then concatenate the next flow, if you don't need to return the void generics. Event has two generics, P and R. the first is the return value type of the previous flow, and the second is the return type of the current flow. The await exec method is to end the current event flow and substitute the result into the next flow.\n\n\u003ePrint two sentences\n\n```\nFlow.create(new Event\u003cVoid,Void\u003e() {\n                    @Override\n                    public void run(Flow flow, Void aVoid, Await\u003cVoid\u003e await) {\n                        System.out.println(\"this is first flow\");\n                        await.exec(null);\n                    }\n                    \n                }).then(new Event\u003cVoid, Void\u003e() {\n                    @Override\n                    public void run(Flow flow, Void aVoid, Await\u003cVoid\u003e await) {\n                        System.out.println(\"this is two flow\");\n                        await.exec(null); \n                    }\n                }).start();\n```\n\n\u003e Lambda simple\n\n```\nFlow.create((NoneEvent) (flow, await) -\u003e {\n                    System.out.println(\"this is first flow\");\n                    await.exec(); \n                }).then((NoneEvent) (flow, await) -\u003e {\n                        System.out.println(\"this is two flow\");\n                        await.exec();\n                }).start();\n```\n\u003e Addition of two numbers\n\n```\n Flow.create((FirstEvent\u003cInteger\u003e) (flow, await) -\u003e \n                        await.exec(3))\n                     .then((Event\u003cInteger, Integer\u003e) (flow, integer, await) -\u003e \n                             await.exec(integer + 5))\n                     .resultThen((flow, result) -\u003e \n                             System.out.println(\"total is\"+result))\n                     .start();\n```\nThe resultthen method returns the result of the current flow, which can be obtained by using resultthen after each flow. If an exception is encountered, it can be thrown through the flow throwexception method. It can be processed immediately after the flow or at the end of the flow. Finally then is a notification that the event flow ends.\n\n\n```\n Flow.create((FirstEvent\u003cInteger\u003e) (flow, await) -\u003e\n                        await.exec(0))\n                     .then((Event\u003cInteger, Integer\u003e) (flow, perVal, await) -\u003e{\n                         if(perVal == 0){\n                             flow.throwException(\"Dividend cannot be 0!\");\n                         }else{\n                             await.exec(perVal/5);\n                         }\n                     })\n                     .resultThen((flow, result) -\u003e\n                             System.out.println(\"total is\"+result))\n                     .catchThen((flow, e) -\u003e\n                             System.out.println(e.getMessage()))\n                        .finallyThen((flow, await) -\u003e \n                              System.out.println(\"this is flow end\")).start();\n```\n\n###### Switching thread\nUse the on method to switch threads. On passes a switch parameter, representing the next flow switch. If two parameters, it means that the current flow and the next flow switch threads. Of course, you can also implement the converter interface to achieve other functions.\n```\nFlow.create((FirstEvent\u003cInteger\u003e) (flow, await) -\u003e\n                        await.exec(0))\n                     .on(AndroidMain.get(),SingleThread.get())   \n                     .then((Event\u003cInteger, Integer\u003e) (flow, perVal, await) -\u003e{\n                         if(perVal == 0){\n                             flow.throwException(\"Dividend cannot be 0!\");\n                         }else{\n                             await.exec(perVal/5);\n                         }\n                     })\n                     .on(AndroidMain.get())\n                     .resultThen((flow, result) -\u003e\n                             System.out.println(\"total is\"+result))\n                     .on(AndroidMain.get())\n                     .catchThen((flow, e) -\u003e\n                             System.out.println(e.getMessage()))\n                     .on(SingleThread.get())\n                     .finallyThen((flow, await) -\u003e\n                              System.out.println(\"this is flow end\")).start();\n```\n\n###### The collection result is converted to multiple streams\n\n```\nFlow.each((FirstEvent\u003cList\u003cString\u003e\u003e) (flow, await) -\u003e {\n                    ArrayList\u003cString\u003e list = new ArrayList\u003c\u003e();\n                    list.add(\"1\");\n                    list.add(\"2\");\n                    list.add(\"3\");\n                    await.exec(list);\n                }).then((LastEvent\u003cString\u003e) (flow, s, await) -\u003e {\n                    System.out.println(\"this is\"+s);\n                }).start();\n```\n###### Multiple stream results converted to one stream\n\n\n```\n Flow.merge((flow, await) -\u003e await.exec(1),\n                        (flow, await) -\u003e await.exec(2),\n                        (flow, await) -\u003e await.exec(2)).resultThen((flow, result)\n                        -\u003e  System.out.println\"result\"+result)).start();\n```\n\n###### condition selection\nReinitiate flow flow according to condition judgment (return parameters can be different)\n\n```\n Flow.create((NoneEvent) (flow,await) -\u003e{\n                    System.out.println(\"start\");\n                    await.exec();\n                })\n                 .on(SingleThread.get())\n                 .conditionThen((VoidCondition) () -\u003e false,\n                                Flow.create((NoneEvent) (flow,await) -\u003e {\n                                    System.out.println(\"this is true\");\n                                    await.exec();\n                                }),\n                                Flow.create((NoneEvent) (flow,await) -\u003e {\n                                    System.out.println(\"this is false\");\n                                    await.exec();\n                                })).start();\n```\nThe flow flow is executed according to the condition judgment and can be combined. (return parameters must be consistent)\n```\nFlow.condition2(() -\u003e isGo, (FirstEvent\u003cInteger\u003e) (flow, await) -\u003e {\n                    System.out.println(\"this is true\");\n                    await.exec(1);\n                }, (flow, await) -\u003e {\n                    System.out.println(\"this is false\");\n                    await.exec(0);\n                }).resultThen((flow, result) -\u003e  System.out.println(\"result\"+result))\n                        .watch(this).start();\n```\n\n\n###### Lifecycle unbound\nThrough the flow watch method. The observed must implement the ilifeobservable interface.\n\n```\n  Flow.create((FirstEvent\u003cInteger\u003e) (flow, await) -\u003eawait.exec(0)) \n      .watch(this).start();\n```\n\n### Use\n\n\n```\nallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url 'https://www.jitpack.io' }\n\t\t}\n\t}\n\t\n\timplementation 'com.github.huangyanbin:SmartFlow:Tag'\n```\n\n### summary\nflow has been introduced into the actual project, which provides some simplified classes, and can also abstract its own Event with the project network request framework, which is almost the same as that of JS's then. Later, adjust according to the actual needs, in the test.\n\n\n\n\n\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuangyanbin%2Fsmartflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuangyanbin%2Fsmartflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuangyanbin%2Fsmartflow/lists"}