Click on me. Here’s the code

why

In code, we often encounter asynchronous method nesting. For example, after submitting the file, submit the form, submit the data according to whether it is successful and then make other logical processing. Kotlin introduced the concept of coroutines, using syntactic sugar to solve this problem. There is also async/await in javaScript to make asynchrony look like synchronization. I haven’t found this feature yet in Java, which makes writing asynchronous nesting feel like hell. During the Spring Festival, I tried to solve this problem according to my own ideas, and built a Flow wheel, so I wrote a small Flow frame.

idea

Thinking of code in terms of life, method nesting is very similar to the principle of water flow, we think of each asynchronous as a pipe, water flows through a pipe, each pipe can process water conversion. The process of transformation is thought of as an Event. In the wrapper event, we can do thread conversion, event conversion, merge and split, etc. If an exception is encountered, the flow is terminated directly.

function

Simple to use

The Flow static create method creates a Flow, then concatenates the next Flow, and returns a Void generic if not required. Event has two generic types P and R. The first is the return type of the previous Flow and the second is the return type of the current Flow. The await exec method terminates the current stream of events and substitutes the result into the next stream.

Print two sentences

Flow.create(new Event<Void,Void>() {
                    @Override
                    public void run(Flow flow, Void aVoid, Await<Void> await) {
                        System.out.println("this is first flow");
                        await.exec(null);
                    }
                    
                }).then(new Event<Void, Void>() {
                    @Override
                    public void run(Flow flow, Void aVoid, Await<Void> await) {
                        System.out.println("this is two flow");
                        await.exec(null); 
                    }
                }).start();
Copy the code

Lambda simplification

Flow.create((NoneEvent) (flow, await) -> {
                    System.out.println("this is first flow");
                    await.exec(); 
                }).then((NoneEvent) (flow, await) -> {
                        System.out.println("this is two flow");
                        await.exec();
                }).start();
Copy the code

The two together

 Flow.create((FirstEvent<Integer>) (flow, await) -> 
                        await.exec(3))
                     .then((Event<Integer, Integer>) (flow, integer, await) -> 
                             await.exec(integer + 5))
                     .resultThen((flow, result) -> 
                             System.out.println("total is"+result))
                     .start();
Copy the code

The resultThen method returns the result of the current flow. After each flow, use the resultThen method to obtain the result of the flow. If an exception is encountered, it can be thrown through the flow throwException method, either immediately after the flow catchThen or at the end of the flow catchThen. FinallyThen is a notification that the event stream ends.

 Flow.create((FirstEvent<Integer>) (flow, await) ->
                        await.exec(0))
                     .then((Event<Integer, Integer>) (flow, perVal, await) ->{
                         if(perVal == 0){
                             flow.throwException("Dividend cannot be 0!");
                         }else{
                             await.exec(perVal/5);
                         }
                     })
                     .resultThen((flow, result) ->
                             System.out.println("total is"+result))
                     .catchThen((flow, e) ->
                             System.out.println(e.getMessage()))
                        .finallyThen((flow, await) -> 
                              System.out.println("this is flow end")).start();
Copy the code
Switch threads

Threads can be switched using the flow on method, where ON passes a Converter parameter representing the next stream switch. If there are two Converter parameters, it means that the current stream and the next stream both switch threads. Of course, you can also implement the Converter interface for other functions.

Flow.create((FirstEvent<Integer>) (flow, await) ->
                        await.exec(0))
                     .on(AndroidMain.get(),SingleThread.get())   
                     .then((Event<Integer, Integer>) (flow, perVal, await) ->{
                         if(perVal == 0){
                             flow.throwException("Dividend cannot be 0!");
                         }else{
                             await.exec(perVal/5);
                         }
                     })
                     .on(AndroidMain.get())
                     .resultThen((flow, result) ->
                             System.out.println("total is"+result))
                     .on(AndroidMain.get())
                     .catchThen((flow, e) ->
                             System.out.println(e.getMessage()))
                     .on(SingleThread.get())
                     .finallyThen((flow, await) ->
                              System.out.println("this is flow end")).start();
Copy the code
CollectionThe result is converted into multiple streams
Flow.each((FirstEvent<List<String>>) (flow, await) -> {
                    ArrayList<String> list = new ArrayList<>();
                    list.add("1");
                    list.add("2");
                    list.add("3");
                    await.exec(list);
                }).then((LastEvent<String>) (flow, s, await) -> {
                    System.out.println("this is"+s);
                }).start();
Copy the code
Multiple stream results are converted into one stream
 Flow.merge((flow, await) -> await.exec(1),
                        (flow, await) -> await.exec(2),
                        (flow, await) -> await.exec(2)).resultThen((flow, result)
                        ->  System.out.println"result"+result)).start();
Copy the code
To choice

Re-initiate Flow according to conditions (return parameters can be different)

 Flow.create((NoneEvent) (flow,await) ->{
                    System.out.println("start");
                    await.exec();
                })
                 .on(SingleThread.get())
                 .conditionThen((VoidCondition) () -> false,
                                Flow.create((NoneEvent) (flow,await) -> {
                                    System.out.println("this is true");
                                    await.exec();
                                }),
                                Flow.create((NoneEvent) (flow,await) -> {
                                    System.out.println("this is false");
                                    await.exec();
                                })).start();
Copy the code

Flow flows are executed according to the criteria and can be merged together. (Return parameters must be consistent)

Flow.condition2(() -> isGo, (FirstEvent<Integer>) (flow, await) -> {
                    System.out.println("this is true");
                    await.exec(1);
                }, (flow, await) -> {
                    System.out.println("this is false");
                    await.exec(0);
                }).resultThen((flow, result) ->  System.out.println("result"+result))
                        .watch(this).start();
Copy the code
Life cycle unbinding

Through the flow Watch method. The observed must implement the ILifeObservable interface.

  Flow.create((FirstEvent<Integer>) (flow, await) ->await.exec(0)) 
      .watch(this).start();
Copy the code

conclusion

The framework also provides some simplified classes, and can also abstract its own events from the project web request framework, so that they are almost identical to the JS web THEN. Follow-up adjustment according to the actual demand, the test.