In the last article, I recorded the implementation of static pages of the Open source Chinese client based on Flutter, mainly the IMPLEMENTATION of UI, without any network request, data loading, storage and other aspects. This article is a record of the web requests and data storage and loading methods used in the project. I hope I can help beginners with Flutter while reviewing the old and the new.

The index The article
1 Write an open Source Chinese Client based on Flutter from 0 (1)

Flutter build | nuggets technical essay introduction and development environment
2 Write an open Source Chinese Client based on Flutter from 0 (2)

Dart Grammar Basics
3 Write an open Source Chinese Client based on Flutter from 0 (3)

Introduction to Flutter & Common Widgets
4 Write an open Source Chinese Client based on Flutter from 0 (4)

Foundation of Flutter layout
5 Write an open Source Chinese Client based on Flutter from 0 (5)

Set up the overall layout framework of the App
6 Write an open Source Chinese Client based on Flutter from 0 (6)

Implementation of various static pages
👉 7 Write an open Source Chinese Client based on Flutter from 0 (7)

App network requests and data stores
8 Write an open Source Chinese Client based on Flutter from 0 (8)

Use of plug-ins

Web requests in Flutter

The Web request library is built into the Flutter and can be imported directly to use:

import 'package:http/http.dart' as http;
Copy the code

A simple GET request code looks like this:

import 'package:http/http.dart' as http;

main() async {
  http.Response res = await http.get("https://cn.bing.com");
  print(res.body); // Print the string data returned by the get request}Copy the code

The string data returned by the request is printed in the console.

In addition, there are some open source network request libraries, because the author has not used, so I will not detail in this article.

The open source Chinese client based on The Flutter uses the built-in Web request library with some simple encapsulation. The main code is in the lib/util/ netutils. dart file. The code is as follows:

import 'dart:async';
import 'package:http/http.dart'as http; Class NetUtils {// get (); // get (); // get (); Static Future<String> get(String URL, {Map<String, String> params}) async {if(params ! = null && params.isnotempty) {StringBuffer sb = new StringBuffer("?");
      params.forEach((key, value) {
        sb.write("$key" + "=" + "$value" + "&");
      });
      String paramStr = sb.toString();
      paramStr = paramStr.substring(0, paramStr.length - 1);
      url += paramStr;
    }
    http.Response res = await http.get(url);
    returnres.body; Static Future<String> post(String URL, {Map<String, String> params}) async { http.Response res = await http.post(url, body: params);returnres.body; }}Copy the code

The method to use the utility class is also simple, as shown in the following code:

import 'util/NetUtils.dart';

main() {
  Map<String, String> map = new Map();
  map['name'] = 'zhangsan';
  map['age'] = '20';
  NetUtils.get("http://www.baidu.com", params: map).then((res) {
    print(res);
  });
}
Copy the code

Data storage in the Flutter

Generally, data storage in mobile application development is basically file, database and other methods. Flutter does not provide an API to directly operate the database, but there are third-party plug-ins, such as SQflite, that can be used. For details about how to use this plug-in, see here. Since the database is not used in the Open source China Client project based on Flutter, I will not elaborate on these.

For this project, the user information is stored using The Android like SharedPreferences provided by Flutter. This library is provided as a plug-in and is not built into the Flutter, so we need to configure the plug-in for the project. In the pubspec.yaml file, add the following configuration:

dependencies:
  flutter:
    sdk: flutter
    
  shared_preferences: "^ 0.4.1"
Copy the code

Then run the flutter packages get command to automatically install the plugin. If you are using AndroidStudio as a development tool, when the pubspec.yaml file has been modified, you will be prompted automatically at the top of the page.

Once the plug-in is installed, it’s easy to use, as shown in the following code:

import 'package:shared_preferences/shared_preferences.dart';

main() async {
  SharedPreferences sp = await SharedPreferences.getInstance();
  sp.setString("name"."zhangsan");
  sp.setInt("age", 20);
  sp.setBool("isLogin".false);
  sp.setDouble("price", 100.5);
}
Copy the code

To get a piece of stored data, simply use sp.get(key). The home page for the shared_Preferences plug-in is here.

Pub. Flutter -io.cn/ is a repository of flutter plugins for publishing plugins related to dart or Flutter. If we need to implement a feature that Flutter does not provide, we can search for the relevant keywords on the site and someone may have published a library that does exactly what we need.

Network requests and data storage in Flutter are briefly explained above, and the following combined items show how to load network data, how to store user information and other data.

Loads a list of information from the network and displays it

In the last post, I documented how to display a list of information, but it was a completely static list of information, and the data in it was all fake data for testing. This post documented how to get real data from the interface and display it.

In the project of the open source China client based on Flutter, the interface provided by the official openapi of the open source China is not used in the information list because the data provided by the official openapi of the open source China is relatively small. The author captured the website data with python, and the interface is deployed on the cloud server in Hong Kong. Please understand if there is a slow access. In addition, the interface is not authenticated. Do not frequently request the interface.

Display Loading in Loading

In this case, add a variable called listData to NewsListPage. If this variable is null, display Loading. Otherwise, display Loading. If Loading is performed at the same time as requesting data from the network, then update listData with setState. The main code is as follows (NewsListPage.

@Override Widget build(BuildContext context) {// Loading is displayed when no data is availableif (listData == null) {
      returnThe new Center (/ / CircularProgressIndicator is a circular Loading progress bar child: new CircularProgressIndicator (),); }elseListView = new ListView.builder(itemCount: listdata.length * 2, itemBuilder: (context, i) => renderRow(i), controller: _controller, ); // The RefreshIndicator adds the drop down refresh capability to the ListView. The onRefresh parameter is passed in a method to be called when the drop down refresh occursreturn new RefreshIndicator(child: listView, onRefresh: _pullToRefresh);
    }
  }
  
  @override
  void initState() {
    super.initState();
    getNewsList(false); GetNewsList (bool isLoadMore) {String URL = api.news_list; // curPage is a member variable defined in NewsListPageState that represents the index URL += of the currently loaded page"? pageIndex=$curPage&pageSize=10";
    NetUtils.get(url).then((data) {
      if(data ! = null) {// To parse the JSON string returned by the interface into the map type, import the package: import'dart:convert';
        Map<String, dynamic> map = json.decode(data);
        if (map['code'] == 0) {var MSG = map['msg']; ListTotalSize = MSG [listTotalSize = MSG]'news'] ['total']; Var _listData = MSG [var _listData = MSG [var _listData = MSG ['news'] ['data'];
          var _slideData = msg['slide'];
          setState(() {
            if(! IsLoadMore) {listData = _listData; listData = _listData; slideData = _slideData; }elseList list1 = new List(); // Select * from List where list1 = new List(); List1. addAll(listData); List1. addAll(_listData); // Check whether all data is obtained. If yes, display the bottom data"There are limits to what I can do."layoutif(list1.length >= listTotalSize) { list1.add(Constants.END_LINE_TAG); } listData = list1; // slideData = _slideData; }}); }}}); }Copy the code

In the code above, there is different logic for displaying Loading and displaying the list of data, and then there is more logic for Loading, but when to load more data? Obviously, you should listen for the list to scroll, and actively load the next page of data when the list rolls to the bottom.

Load the next page of data

In the above code, when we create the ListView, we pass in a controller parameter, and this controller is passed in to listen for the list scroll event, which is a ScrollController object, We define this variable in the NewsListPageState class and initialize it:

ScrollController _controller = new ScrollController();
Copy the code

To listen for an event to see if the list scrolls to the bottom, add a Listener to the controller. Add the following code to the NewsListPageState class constructor:

  NewsListPageState{{_controller. AddListener () ()/var/says the biggest scrolling list distance maxScroll = _controller. Position. MaxScrollExtent; / / said currently has scroll down the list of distance var pixels = _controller. Position. The pixels. // If the two values are equal, scroll to the end, and if the list has not loaded all the dataif(maxScroll == pixels && listData.length < listTotalSize) { // scroll to bottom, get next page data curPage++; // Add 1 to the current page indextrue); // Get the next page}}); }Copy the code

Add the drop-down refresh capability to the ListView

The build method returns with a layer of refreshindicators wrapped around the ListView:

return new RefreshIndicator(child: listView, onRefresh: _pullToRefresh);
Copy the code

The _pullToRefresh method is called when a pulltorefresh is performed, and the body of the method looks like this:

  Future<Null> _pullToRefresh() async {
    curPage = 1;
    getNewsList(false);
    return null;
  }
Copy the code

Note that the onRefresh parameter requires data of type Future

, so the _pullToRefresh above returns Future

.

The modified information list is shown in the following GIF (the image is relatively large, and the loading will be a little slow) :

The user data is saved after login

Since the openapi of open source China needs to be called to obtain the movement information, comment movement and so on, and these interfaces all require AccessToken and user id, we must save the data of the user after login, so that the data can be obtained when it is needed. The details of how to do this will be explained in the next article, Using the Flutter plugin. This section ignores the login process for the moment and only explains how to save user information after login.

To manage SharedPreferences, create a new tool class DataUtils. The file directory is lib/util/ datautils.dart. The following information is returned after the open Source China OpenAPI call interface is successfully logged in:

The field name The field type instructions
access_token String Access_token value
refresh_token String Refresh_token value
uid int The UID of the authorized user
tokenType String Access_token type
expires_in int Timeout duration (in seconds)

To save this information in SharedPreferences, declare the key for each field in DataUtils as follows:

  static final String SP_AC_TOKEN = "accessToken";
  static final String SP_RE_TOKEN = "refreshToken";
  static final String SP_UID = "uid";
  static final String SP_IS_LOGIN = "isLogin"; // SP_IS_LOGIN Indicates whether to log in. Static Final String SP_EXPIRES_IN ="expiresIn";
  static final String SP_TOKEN_TYPE = "tokenType";
Copy the code

Then provide a static method to save this information once:

Static saveLoginInfo(Map data) async {if(data ! = null) { SharedPreferences sp = await SharedPreferences.getInstance(); String accessToken = data['access_token'];
      await sp.setString(SP_AC_TOKEN, accessToken);
      String refreshToken = data['refresh_token'];
      await sp.setString(SP_RE_TOKEN, refreshToken);
      num uid = data['uid'];
      await sp.setInt(SP_UID, uid);
      String tokenType = data['tokenType'];
      await sp.setString(SP_TOKEN_TYPE, tokenType);
      num expiresIn = data['expires_in'];
      await sp.setInt(SP_EXPIRES_IN, expiresIn);

      await sp.setBool(SP_IS_LOGIN, true); // SP_IS_LOGIN indicates whether to log in}}Copy the code

After successful login, you can call openAPI of Open Source China to obtain user information. Similar to the above, first define the key corresponding to each field of user information:

  static final String SP_USER_NAME = "name";
  static final String SP_USER_ID = "id";
  static final String SP_USER_LOC = "location";
  static final String SP_USER_GENDER = "gender";
  static final String SP_USER_AVATAR = "avatar";
  static final String SP_USER_EMAIL = "email";
  static final String SP_USER_URL = "url";
Copy the code

We won’t go into detail here, but we’ll provide a static method that saves user information once:

Static Future<UserInfo> saveUserInfo(Map data) async {if(data ! = null) { SharedPreferences sp = await SharedPreferences.getInstance(); String name = data['name'];
      num id = data['id'];
      String gender = data['gender'];
      String location = data['location'];
      String avatar = data['avatar'];
      String email = data['email'];
      String url = data['url'];
      await sp.setString(SP_USER_NAME, name);
      await sp.setInt(SP_USER_ID, id);
      await sp.setString(SP_USER_GENDER, gender);
      await sp.setString(SP_USER_AVATAR, avatar);
      await sp.setString(SP_USER_LOC, location);
      await sp.setString(SP_USER_EMAIL, email);
      await sp.setString(SP_USER_URL, url);
      UserInfo userInfo = new UserInfo(
        id: id,
        name: name,
        gender: gender,
        avatar: avatar,
        email: email,
        location: location,
        url: url
      );
      return userInfo;
    }
    return null;
  }
Copy the code

UserInfo is an entity class defined in lib/model/. The code is as follows:

Class UserInfo {String gender; String name; String location; num id; String avatar; String email; String url; UserInfo({this.id, this.name, this.gender, this.avatar, this.email, this.location, this.url}); }Copy the code

In order to easily retrieve the saved user information and AccessToken data and determine whether the user is currently logged in, we provide three static methods for DataUtils:

/ / get the user information static Future < the UserInfo > getUserInfo () async {SharedPreferences sp = await SharedPreferences. GetInstance (); bool isLogin = sp.getBool(SP_IS_LOGIN);if(isLogin == null || ! isLogin) {return null;
    }
    UserInfo userInfo = new UserInfo();
    userInfo.id = sp.getInt(SP_USER_ID);
    userInfo.name = sp.getString(SP_USER_NAME);
    userInfo.avatar = sp.getString(SP_USER_AVATAR);
    userInfo.email = sp.getString(SP_USER_EMAIL);
    userInfo.location = sp.getString(SP_USER_LOC);
    userInfo.gender = sp.getString(SP_USER_GENDER);
    userInfo.url = sp.getString(SP_USER_URL);
    returnuserInfo; } / / is logged in the static Future < bool > isLogin () is async {SharedPreferences sp = await SharedPreferences. GetInstance (); bool b = sp.getBool(SP_IS_LOGIN);returnb ! = null && b; } accesstoken static Future<String> getAccessToken() async {SharedPreferences sp = await SharedPreferences.getInstance();return sp.getString(SP_AC_TOKEN);
  }
Copy the code

If a user logs out, the saved user information must be cleared:

/ / remove the login information static clearLoginInfo () async {SharedPreferences sp = await SharedPreferences. GetInstance (); await sp.setString(SP_AC_TOKEN,"");
    await sp.setString(SP_RE_TOKEN, "");
    await sp.setInt(SP_UID, -1);
    await sp.setString(SP_TOKEN_TYPE, "");
    await sp.setInt(SP_EXPIRES_IN, -1);
    await sp.setBool(SP_IS_LOGIN, false);
  }
Copy the code

The source code

All source code related to this article is available on GitHub as the V0.3 branch of the Demo-Flutter – OSC project.

Afterword.

This article mainly describes the web request and data storage method of the Open source Chinese client app based on The Flutter. Please forgive me if I am not clear. If you have any questions, please let me know. The next post will document the use of plug-ins in Flutter.

My open source project

  1. Google Flutter based on the open source Chinese client, hope you give a Star support, source code:
  • GitHub
  • Yards cloud

  1. Tetris based on the Flutter small game, I hope you give a Star support, source:
  • GitHub
  • Yards cloud

In the previous The next article
Write an open Source Chinese Client based on Flutter from 0 (6)

— Implementation of individual static pages
Write an open Source Chinese Client based on Flutter from 0 (8)

— Use of plug-ins