当前位置：网站首页>Bolt's practice of route management of flutter (page decoupling, process control, function expansion, etc.)
Bolt's practice of route management of flutter (page decoupling, process control, function expansion, etc.)
2020-12-09 10:44:42 【osc_ 0kdyznad】
In the major mobile development framework （Android、iOS、Flutter、React Native…） in , Routing management is always UI One of the hottest topics in Architecture .
One big reason is that the application's pages will Inevitably more , We can use BLOC,MVP,MVI And so on UI Reasonable separation from business logic to achieve a good architecture , But how to integrate a new page into the existing structure is still a big problem .
Android in , Except for the traditional Intent / Fragment Way of doing business ,Google Also in the Jetpack Technical secondary school provides for the management of complex page logic Navigation Components ,Flutter Also launched Navigator2.0 To help us adapt to different routing scenarios .
This article comes from abroad Bolt Team article （ original text https://medium.com/flutter-community/navigation-done-right-a-case-for-hierarchical-routing-with-flutter-ca0aac1275ad ）, Summed up their team building Flutter When applied , Some ideas and solutions for managing routing pages , I think it's worth learning from , With the consent of the author , Combined with my own understanding of translation published .
notes ： This article is not based on Flutter Navigator2.0.
Break the coupling between single pages
If we need to develop an app , You need to fill in a series of personal information before you can continue , So we need to develop a series of different pages for users to fill in different information , Like hobbies 、 Location 、 Personal signature and so on , After users fill in these information and click Submit, they also need to call the interface to pass the data to the back end .
The easiest way to do this is to put one on each page “ continue ” Button , The user clicks and triggers the routing operation , as follows ：
Click here , When it comes to the last form page , You can submit the final result . here , How the user input data is transferred between routes is the second , We can temporarily store in memory somewhere , What's more important is how to perform the following operations after a page performs its duties .
There is an interesting scene , If we want to continue to develop an entry page that allows users to edit this information , We're going to redevelop a series of editing pages , Or reuse the logic before , Edit the information step by step ？
Obviously , If the user only wants to change a user name , And if you have to go through this whole series of processes , It's going to have a huge impact on the experience , therefore , We can reuse the previous page as shown in the figure below UI And can modify each item of information individually , When in edit mode , You can click on the “ preservation ” Update relevant information directly ：
here , You can modify the callback function by clicking the button , As shown below , Determine whether you are currently in edit mode ：
Although the function is realized , But in this simple example , The code is already a little bloated , In the actual project , We may also handle more routing related operations , This way of responding to the user's operation is not very particular .
here , Each page coincides with the next page , And each page is forced to rely on the type of data it needs to submit , In large projects , We usually need to reduce this coupling as much as possible 、 rely on , And the same kind of behavior can be extracted separately and put together .
in addition , If we want to adjust the sequence of steps in the future , Introduce new steps , There will be a lot of changes to the original code ; And if there are similar types of information （ If you fill in the user name 、 Personalized signature pages contain only one title Text An input box TextField, You can only write a different UI Components , such , In terms of code reusability and extensibility , It doesn't make sense .
therefore , In this paper, we will focus on how to decouple routing related operations from other business logic , Reduce dependence .
Abstract exit point
A simple solution can break this tight coupling of individual screens . This approach needs to be based on , We've determined what to do next when the current page performs its duties , Then the exit point is abstracted out .
First , We can write an abstract class LocationInputScreenListener, This class is dedicated to listening to Fill in the position page Related routing operations in , Abstract the operation of what it should do next after it performs its duties ：
after , We can use the way of interface to handle the event of page Jump , As shown below ：
such , In addition to relying on LocationInputScreenListener Outside , It's like a completely independent individual .
that , How components get this Listener, Of course, we can pass it layer by layer through the constructor , A better way is to use Flutter The hereditability of states in , because Open the page / Change page state The operation of is entirely made up of the upper components decision / Trigger Of , therefore , We can put some Listener Put it in an ancestor node , then , Used in child components
context.findAncestorStateOfType In getting it .
such , We can use the following ways for LocationInputScreenListener Empower , Make it a component state ：
As shown in the following code ,AncestorState Realized LocationInputScreenListener after , We can use... In the subcomponents
context.findAncestorStateOfType<LocationInputScreenListener> Find the state object directly , And use one of the methods ：
such , This interface becomes the established rule of page routing , If you want to perform some routing operations, you need to implement the relevant interface . Usually , The interface can be implemented by the direct parent component of the component , You can also implement multiple interfaces to respond to events of different parents , The sample application contains an example ：LoggedInFlowController （https://github.com/yarolegovich/flutter_navigation/blob/master/lib/root/loggedin/logged_in_flow_controller.dart#L12） Implemented in Information editing events （OnEditProfileClickedListener） and RootState （https://github.com/yarolegovich/flutter_navigation/blob/master/lib/root/root.dart#L18） To deal with the Logout event （OnLoggedOutListener）, Both events were caused by profile Page response .
besides , This way of abstracting exit points also greatly simplifies project collaboration , Because the developer of a feature doesn't have to wait for the context of the feature to be presented , Just define the interface and build your own functionality , And then put it in the right place .
Part of the logic is extracted into the unified ancestor component ,UI Presentation and routing logic may still overlap , At this time , We can go through Flow controller （flow controller） This design pattern solves this problem .
We can think of the application as a tree , The leaf node represents a single page , Other nodes represent abstract flows . Back to the example above , Of this application “ Routing tree ” It can be represented by the following diagram ：
Strictly speaking , This is a rooted acyclic digraph , There is at least one reachable path from the root to any leaf node , And nodes can be reused , Show... In multiple contexts .
Modeling in this way , We can see and Individual pages related to a single process , For every process , We can create one “ empty ” The ancestors , Its sole responsibility is to coordinate the process , For example, determine which page should be displayed at a certain time .
The biggest benefit of this model is that it can Unify the logic of routing operations within the scope , There is a unified local management for each process , Including the order of page presentation 、 Conditions 、 data 、 Transition animation and so on . Not only does it give us a clear perspective to manage routing state , And make the code easier to expand and maintain , here , We can change the routing order according to the demand , Introduce or insert new routing pages into the process, etc .
Another big benefit is , Managing the routing stack in each control flow is much simpler than managing the entire application's routing stack , here , In the stack, there are only components related to the process , When performing some less trivial stack operations （ Such as popUntil） when , This greatly reduces the possibility of errors and their costs .
The process controller also maintains that multiple screen pages can share some common logic or UI Components . stay Flutter In the project , My work also included keeping the logic for displaying dialog boxes and bottom navigation bars in the basic flow controller class , In order to be quick , Easy access to these components .
Implement the basic process controller BaseFlowController
below , I want to show you a more general example , Readers can use it as a basis to expand the use of .
As mentioned above , The process controller is responsible for coordinating the collaborative processes between pages ,BaseFlowController Use a basic empty stack as an example , In more complex applications , If it contains multiple stacks flow, At this time, the application can also display multiple different components at the same time .
In your own FlowController in , It should contain only multiple routing containers （ especially Navigator） And some methods that can operate container routing stack directly （ adopt key）,
in addition , The process controller may also contain elements shared among multiple routes , Like the bottom navigation bar 、 Banners that pop up notices, etc , This kind of situation will not be considered in this paper , Leave it to the reader to practice on their own .
FlowControllerState Part of the code is as follows , You can go to GitHub（https://github.com/yarolegovich/flutter_navigation） Check out the full code ：
The above code shows the basic functions of the process controller , Let's continue to explore the specific implementation process .
Expand Navigator The function of
_navStack, Optional , Save the current routing state , With it, we can do a lot of native for the current routing state Navigator There is no specific function provided , If the following methods are provided ：
Hide the implementation
_navKey, To access and manipulate the navigator （Navigator）, You should avoid exposing it directly to subcomponents , Instead, it provides ways to update the State , In the following code pop、push etc. ：
such , We can easily add Log And more extra general functions , And guarantee in the abstract layer _navStack The correctness of the State .
Life cycle perception
_routeObserver stay FlowController Not used in , But it's good for implementing states that are sensitive to lifecycle States , We can perform some visibility operations based on these States , For example, turn polling on and off when the application returns in the background ：
In the example application in this article , I'll use it to Update profile page status （https://github.com/yarolegovich/flutter_navigation/blob/master/lib/root/loggedin/home/profile/profile_page.dart#L93）, here , When the user changes his personal information and returns from the edit page , The user can then see the latest data .
Handle the return button
Last , And the trickiest part is dealing with the return button . If we just Navigator Package to WillPopScope In the component , So the top one widget All return events will be received , And ignore the process controllers below .
in addition ,findAncestorStateOfType Very efficient , Because in the worst case , The number of nodes it accesses is equal to the height of the component tree , However , If we pass an event that returns a button from the upper node to the lower level , Find the right consumer , In the worst case, you need to traverse the nodes of the whole tree .
therefore , To avoid that , We can use only one WillPopScope And a list of status to listen for the return button event . The process controller itself can register and log off ,WillPopScope The container is responsible for distributing event scheduling to each registered component , Here's the code ：
The lower , We can consume this event in the process controller ：
such , The state object of the root component is mixed with PopScopeHost , And will onWillPop Method passed to WillPopScope after , The function of event distribution can be realized completely ：
Implement process controller
Last , We use ProfileSetupController For example , Take a look at how to create your own process controller using the above abstract classes , as follows ：
here , It's like a lot of architecture books , This way of code is fully embodied High cohesion and low coupling , The logic related to the routing operation is changed from UI The components are separated .
EditProfileFlowController It's a more complex case （ Information editing page ）, At this point, the program needs to deal with such as updating data , Clear the page and so on （ For the complete code, see ：https://github.com/yarolegovich/flutter_navigation/blob/master/lib/root/loggedin/editprofile/profile_edit_flow_controller.dart#L22）.
For a complete sample project code, see ：https://github.com/yarolegovich/flutter_navigation
Bolt The team's article was published in Navigator2.0 Before appearance , There are many similarities between them , After practice , This kind of solution also proved to be able to help them enhance the scalability of the application , Adapt to the new needs of continuous development .
- OPTIMIZER_ Trace details
- Using consult to realize service discovery: instance ID customization
- Summary of common string algorithms
- Summary of common algorithms of linked list
- Linked blocking Queue Analysis of blocking queue
- 构建者模式(Builder pattern)
- Builder pattern
- Newbe.ObjectVisitor 样例 1
Newbe.ObjectVisitor Example 1
Farewell to runaway
LeetCode Algorithm 0060 - Permutation Sequence (Medium)
编程基础 - 栈的应用 - 混洗(Stack Shuffling)
LeetCode Algorithm 0060 - Permutation Sequence (Medium)
Fundamentals of programming stack shuffling
[color card] brief analysis of commonly used chromatograms, Chinese traditional color cards, code with RBG, HC
Introduction to mongodb replica set
- My name is mongodb, don't understand me. After reading my story, you will get started!
- Roboguide cracking installation tutorial
- The transformation of town street intelligent street lamp under the industrial intelligent gateway
- Remote smoke monitoring of environmental protection data acquisition instrument under Internet of things
- Flutter 页面中的异常处理ErrorWidget
- Exception handling errorwidget in fluent page
- C语言系统化精讲 重塑你的编程思想 打造坚实的开发基础
- Skywalking series blog 7 - dynamic configuration
- Skywalking series blog 6 - help you write skywalking plug-in
- Blog host_ Automatic renewal of free certificate
- 0x05 - 综合示例，导出 CSV
- 0x05 - synthesis example, export to CSV
- 0x02 - create and cache object visitors
- Fluent round or linear progress bar
- Fluent adds sticky header components to scrolling content
- Typora uses latex to insert mathematical formulas
- How to write a thesis opening report
- Based on C PHP fast IP resolution extension, IP detection
- Click smooth scrolling effect
- HighGo Database触发器使用案例（APP）
- Use case of highgo database trigger (APP)
- Flutter 最常出现的错误
- Flutter's most common mistakes
- 捕获 flutter app的崩溃日志并上报
- Capture and report the crash log of the flutter app
- SQL Server递归查询在Highgo DB中实现 (APP)
- Implementation of SQL Server recursive query in highgo dB (APP)
- About browserlist configuration items