返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Flutter

Flutter Mobile App Rapid Development Practice — State Management, Internationalization, Data Persistence, and Performance Optimization (Part 2)

Continuing from the previous article: Behind Minimalist Poetry: Flutter Mobile App Rapid Development Practice — State Management, Internationalization, Data Persistence, and Performance Optimization (Part 1) The previous article covered project structure, state management, and internationalization. This article continues with data persistence and rough performance optimization. Data Persistence Currently, the more commonly used and mature data persistence solutions in Flutter are shared_preferences and SQFLite. One is an ini config file, the other is an SQLite database. For small apps I tend to use only the former,

曦远 (DealiAxy)约 18 分钟
目录5 个章节

Continuing from the previous article: Behind Minimalist Poetry: Flutter Mobile App Rapid Development Practice — State Management, Internationalization, Data Persistence, and Performance Optimization (Part 1)

The previous article covered project structure, state management, and internationalization. This article continues with data persistence and rough performance optimization.

Data Persistence

Currently, the more commonly used and mature data persistence solutions in Flutter are shared_preferences and SQFLite. One is an ini config file, the other is an SQLite database. For small apps I tend to use only the former—it's more convenient. Sqflite works, but Flutter still doesn't have a really good ORM framework, so you have to write a lot of SQL, which is painful.

So below I'll introduce the simple usage of shared_preferences. For details, see the official site: https://pub.flutter-io.cn/packages/shared_preferences

Add the dependency:

dependencies:
  shared_preferences: ^0.5.6

Here's a simple example from the official site:

SharedPreferences prefs = await SharedPreferences.getInstance();
int counter = (prefs.getInt('counter') ?? 0) + 1;
print('Pressed $counter times.');
await prefs.setInt('counter', counter);

Just copying the official example isn't enough, of course. What I want to talk about for data persistence is this—the approach used in this project.

Remember the json model module from the previous article? The object serialization and deserialization it provides is very useful for persistence. When saving data, convert the model class to JSON and store it in SharedPreferences. For example:

/// 持久化Profile信息
static saveProfile() => _prefs.setString("profile", jsonEncode(profile.toJson()));

When the app starts, read the JSON data from SharedPreferences and use the model class's JSON constructor to create (deserialize) a model object. Example:

_prefs = await SharedPreferences.getInstance();
var _profile = _prefs.getString("profile");
if (_profile != null) {
      try {
        profile = Profile.fromJson(jsonDecode(_profile));
        // 防止读取出来是null,用于从版本已有profile数据的升级,如果是全新安装的没有这个问题
        profile.darkMode = profile.darkMode ?? false;
      } catch (e) {
        print(e);
      }
}

That completes the data persistence work—very simple.

Next, a bit about project configuration. Whether it's Flutter development or Android development, it's all Google's technology. Google, you know—the servers are all blocked, and most of the Gradle Maven sources are inaccessible too, so compiling an Android APK is always slow. We need to set up domestic mirrors.

Modify android/build.gradle and change the default google() and jcenter() to the following addresses.

repositories {
     // google()
     // jcenter()
     maven { url 'https://maven.aliyun.com/repository/google' }
     maven { url 'https://maven.aliyun.com/repository/jcenter' }
     maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
}

Also modify the android/gradle/wrapper/gradle-wrapper.properties file.

#Wed Dec 11 15:10:31 HKT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip

Change the last line to a domestic server, e.g.: distributionUrl=https\://downloads.gradle-dn.com/distributions/gradle-5.1.1-all.zip—just change the domain.

There's also pub.dev, the Dart package publishing site, which is inaccessible in China, but we have a domestic mirror: https://pub.flutter-io.cn/

Thanks to the folks in the domestic open-source community for their efforts!

There's also migrating to AndroidX, which is another pitfall. You can refer to: Flutter Development: Migrating a Flutter App to AndroidX

Flutter's "Multithreading"

Next, some practices around performance optimization. I put multithreading in quotes in the heading because Dart is single-threaded, similar to JS. In Flutter, the UI and other operations all run on the same thread. If there's a time-consuming operation on the main thread, the UI freezes. Flutter displays at 60 fps by default, so if an operation can't finish within 1/60 of a second, it will affect UI refresh and produce a noticeable stutter.

So how do we solve this? Dart introduced something called Isolate, similar to a thread, but it cannot share memory with the main thread. To share data, you must pass arguments and get return values by copying memory. Compared to multithreading, there are still quite a few limitations in usage.

I won't go into too much detail about Isolates. For details, please see the official docs and experts' blogs. Here I'll record my own practice.

As mentioned earlier, switching between the main thread and an isolate has a high overhead, so to use multithreading while also improving performance, we need to reduce isolate creation. We can use a "thread pool" for load balancing, defining a LoadBalancer in code to store our isolates.

Future<LoadBalancer> loadBalancer = LoadBalancer.create(4, IsolateRunner.spawn);

When using it, create a reusable isolate through the load balancer:

final lb = await loadBalancer;
lb.run(Isolate方法, 参数);

The isolate method is a static method that takes one argument. Since it can only take one argument, if you need to pass multiple arguments you have to define your own protocol. You can write your own class, or pass a dict or list. I prefer passing a dict so I don't have to define a separate class. The result after execution is returned via the return value; I usually also return a dict (map).

Note: Isolates cannot access the main thread's memory. Accessing variables from elsewhere inside an isolate is invalid. Please exchange data by passing arguments and getting return values.

Also, you currently cannot use the print function to print logs, nor output logs to Android logcat via a channel. It's said to be a Flutter bug. The only way is to use the logging tool in the official DevTools. See: https://flutter.dev/docs/testing/code-debugging

To Be Continued

I've written quite a lot without realizing it. There are still some miscellaneous bits left, plus more on performance optimization and app size optimization that I'm still researching and summarizing. I'll continue in the next article~

Welcome to Discuss

For questions, please leave a message on the WeChat official account backend. I'll reply to every message~

_EOF_

Flutter Mobile App Rapid Development Practice — State Management, Internationalization, Data Persistence, and Performance Optimization (Part 2)

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

极简诗词app开发背后:Flutter移动应用快速构建实践——状态管理、国际化、数据持久化、性能优化(一)

前言 在开始之前的提示:虽然Flutter背靠Google这棵大树,但是毕竟还是一个年轻的技术,项目还处于初期阶段,更新非常快,问题也不是一般的多,使用Flutter的话就意味着必须忍受各种奇怪的bug和没有丰富中文资料的头疼,本文不是安利同学们入坑,只是对“极简诗词”app的开发过程进行记录。 另外app已经上架,有兴趣的同学可以下载试试:https://www.coolapk.com/apk/

2022-03-23 · Flutter · 约 1 分钟

使用Flutter设计一个好看的_我_页面

近期遇到一些很烦的琐事,状态比较down,很多原本计划好的事情都耽搁了,实在是难顶…… 看到后台一直有朋友问怎么博客和公众号没有更新,所以我忙完得闲就来更了! 前言 起因是最近重拾以前的旧项目(业余做的,打算有机会自己运营起来)继续完善,然后发现有些界面设计太粗糙了,实在不满意~~(虽然是因为本来功能就不多)~~,然后就着手开始优化~ 应该会写成一系列文章,今天就从App的"我"页面开始吧~ 效果

2021-12-18 · Flutter · 约 1 分钟

把爬虫放到手机上跑!Flutter爬虫框架初探~

最近做毕设需要大量数据训练模型,很多网站又要反爬机制,得爬一会停一会,所以特别慢,要是我用电脑24小时爬虫太费电了,于是想到利用手机~ 然后就想到flutter,安卓苹果旧手机都能利用起来做数据采集。 ok,然后就开始做,折腾了一天做了一个大概的框架。总算可以方便的添加爬虫任务了,集成了配置、日志、数据持久化这些基本的功能,然后封装网络请求、网页解析的功能,用起来还行。 只不过众所周知的,dart

2021-12-18 · Flutter · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…