This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

preface

The previous articles have been about Dio network requests, and our dynamic module is only missing the detail page, but after each successful addition and editing, returning to the list page still needs to be manually refreshed, which does not achieve the effect of “what you see is what you get”. This article describes using the GetIt container plug-in to synchronize data between pages. The knowledge points involved in this paper are as follows:

  • Details page interface construction;
  • Update details view times interface implementation;
  • GetIt introduction;
  • Register global objects with GetIt;
  • Use GetIt to synchronize data between pages.

Details page

On the details page we display dynamic titles, views, images and content. The easiest way to do this is to wrap everything in sequence using a Column component. However, given the fact that the content will be really long (and possibly rich text), it’s more appropriate to use a rolling component wrapper, so let’s use a CustomerScrollView, which uses a Sliver subcomponent rather than a regular ScrollView, The slippage will be much better and smoother, just as one chocolate AD says — smooth.

The page itself is relatively simple, not much to introduce, the specific page hierarchy is shown below. For more information on CustomerScrollView, see the previous article, Introduction to Flutter and Practice (xii) : Using CustomerScrollView for more interesting sliding effects.

  • CustomScrollView
    • slivers
      • Title: UseContainerPackage to adjust the layout.
      • Number of views: Similar to the number of views for the list.
      • Images: To avoid images taking up too much height, limit the image height to 240.
      • Content: Similar to the title, but 2 points smaller

The contents of the child components of the above Slivers are converted to Slivers using the SliverToBoxAdapter. The final interface can be seen in the GIF at the back.

Details view times updated

When we enter the details page, we need to submit the interface to update the viewing times to the back end. Note that some application processing is done by the back end directly increasing the number of views to the database when obtaining the detail interface. While this can reduce the number of requests, the drawback of the back-end processing is that the call to the detail interface is counted directly as a view of the detail page. As a result, when getting the details elsewhere (such as the edit interface), it can lead to multiple statistics, known in industry slang as “brushing traffic.”

Using the front update allows for more precise control, such as how long to stay on the page, or how long to slide to the bottom of the page.

Look at the interface address is the number of update: http://localhost:3900/api/dynamics/view/:id, remember to pull the latest code to run. We will check the number of updates after the success of obtaining the detailed interface. Update the number of views is not very important logic, there is no need to alert the user when an error occurs (to avoid confusion to the user), this is just to print the exception information for troubleshooting during the development process. During the actual production process, the exception information can be uploaded to the exception monitoring background.

if (response.statusCode == 200) {
  setState(() {
    _dynamicEntity = DynamicEntity.fromJson(response.data);
  });
  _updateViewCount();
}
/ /...

void _updateViewCount() async {
  try {
    var response = await DynamicService.updateViewCount(_dynamicEntity.id);
    if (response.statusCode == 200) {
      setState(() {
        _dynamicEntity.viewCount = response.data['viewCount'];
        GetIt.instance.get<DynamicListener>().dynamicUpdated( _dynamicEntity.id, _dynamicEntity, ); }); }}catch (e) {
    print(e.toString()); }}Copy the code

Introduction of GetIt

GetIt itself is a container-managed plug-in originally designed to perform the functions of dependency injection DI and IOC containers, similar to Java Spring’s Bean containers. Because the objects in the container are global, they can be used for data synchronization and are one of the official recommended state management containers for Flutter. Another common plug-in for state management is Provider, which we’ll cover later when we get to state management.

The so-called container is essentially a global Map object. Objects can be stored in the container and retrieved directly when needed, without the need for each user to create their own objects and realize the decoupling of objects.

The basic use of GetIt is simple, as shown below. If the container does not have an object in it, it creates one using the “build object” method. If the container does not have an object in it, it returns the “build object” method.

Note that GetIt is available in many versions and requires a minimum SDK version of the Flutter. The SDK version we are currently using is 2.0.6, so we can only select version 4.0.3 (the latest version is 7.1.2 and requires version 2.12.x or above).

// Register object: usually singletons
GetIt.instance.registerSingleton<T>(T object);
// Register in lazy loading mode
GetIt.instance.registerLazySingleton<T>(FactoryFunc<T> func)
// Get the objects in the container
GetIt.instance.get<T>();
Copy the code

Register dynamically changing listening objects

When dynamic additions or dynamic content changes, we need to update the list. The easiest way is to notify the list to refresh, but that adds network requests. We can update the list by modifying the list data directly. Considering that it is not only the dynamic list page that needs to be updated (such as dynamically embedded in other pages), we abstracted the dynamic update method as an interface, and any object that implements the corresponding interface can invoke the corresponding interface update when it dynamically changes — the so-called interface-oriented programming.

Dart: add a dynamic_listener.dart file and define an abstract interface class DynamicListener. Implement the corresponding interface in _DynamicPageState on the list page.

import 'package:home_framework/models/dynamic_entity.dart';

abstract class DynamicListener {
  void dynamicUpdated(String id, DynamicEntity updatedDynamic);

  void dynamicAdded(DynamicEntity newDynamic);
}
Copy the code

_DynamicPageState implements the two methods of the DynamicListener interface using the implements keyword (and also the with keyword) :

  • New response method: When there is a new dynamic, insert the new dynamic into the beginning;
  • Update method: Replace old dynamic data with new dynamic data.

At the same time, register yourself to the GetIt container in the initState method.

class _DynamicPageState extends State<DynamicPage> implements DynamicListener {
	// ...
	
  @override
  void initState() {
    super.initState();
    // Register with the GetIt container
    GetIt.instance.registerSingleton<DynamicListener>(this);
  }
  
  void dynamicUpdated(String id, DynamicEntity updatedDynamic) {
    int index = _listItems.indexWhere((element) => element.id == id);
    if(index ! =- 1) { setState(() { _listItems[index] = updatedDynamic; }); }}void dynamicAdded(DynamicEntity newDynamic) {
    setState(() {
      _listItems.insert(0, newDynamic);
    });
  }
  
  // ...
}
Copy the code

Data is updated between pages

With the GetIt container, because you can directly get the dynamic list of state managed objects from the container, processing in other pages is relatively simple, the logic is as follows:

  • New page: Called after the new page is successfully addeddynamicAddedMethod to update the list page;
  • Edit page: called after successful editingdynamicUpdatedMethod to update the list page;
  • Details page: update the number of calls after viewingdynamicUpdatedMethod to update the list page.

The code of the three pages is as follows:

// Add page
var response = await DynamicService.post(newFormData);
if (response.statusCode == 200) {
  Dialogs.showInfo(context, 'Add successful');
  GetIt.instance
      .get<DynamicListener>()
      .dynamicAdded(DynamicEntity.fromJson(response.data));
  Navigator.of(context).pop();
}
//-------------------------------------
// Edit the page
if (response.statusCode == 200) {
  Dialogs.showInfo(context, 'Saved successfully');
  // Process the successfully updated service
  _handleUpdated(newFormData);
  Navigator.of(context).pop();
}

// Handle updates and update the dynamic image content only if the image has been updated
void _handleUpdated(Map<String.String> newFormData) {
  _dynamicEntity.title = newFormData['title'];
  _dynamicEntity.content = newFormData['content'];
  if (newFormData.containsKey('imageUrl')) {
    _dynamicEntity.imageUrl = newFormData['imageUrl'];
  }
  GetIt.instance.get<DynamicListener>().dynamicUpdated(
      _dynamicEntity.id,
      _dynamicEntity,
  );
}

//-------------------------------------
// Details page
void _updateViewCount() async {
  try {
    var response = await DynamicService.updateViewCount(_dynamicEntity.id);
    if (response.statusCode == 200) {
      setState(() {
        _dynamicEntity.viewCount = response.data['viewCount'];
        GetIt.instance.get<DynamicListener>().dynamicUpdated( _dynamicEntity.id, _dynamicEntity, ); }); }}catch (e) {
    print(e.toString()); }}Copy the code

Running effect

conclusion

This paper has completed the whole dynamic management business logic, including the new, delete, edit, view times and other functions. Through GetIt container management plug-in and interface definition, data synchronization between pages can be easily and quickly completed. As you can see throughout the series, our code in the network request section has the following problems:

  • A lot of repetitive code: for exampletry... catchThe code block;
  • Exposes the details of Dio;
  • The interface participates in the construction of the business objects and is not separated from the business logic.

In the next chapter, we will gradually complete the refactoring of Dio encapsulation and network request part of the code.