曦远 (DealiAxy)一份私人的文字刊物

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 许可协议。转载请注明出处!

相关文章

初见Flutter!框架简单介绍以及构建可发布的签名Apk包

哈喽!好久不见,算起来我已经一个多月没更新博客了,近期刚刚完成了一个项目,正好抽出时间整理一下学到的东西并且写写博客。 关于flutter 开始使用flutter还是春节后的事情,其实之前很早就想学一下flutter了,毕竟谷歌出的技术总是不会太差的,无奈一直没有时间和做app的需求,这次接触了flutter之后仿佛发现了新大陆,原来开发app还能这么方便,真的颠覆了我原来的认知啊,热更新也太好用

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

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

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

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

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

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

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

讨论

共 0 条

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

加载评论中…