实践小结

[toc]

一、生命周期

该界面前提:

①、StatefulWidget

②、WidgetsBindingObserver

③、@override didChangeAppLifecycleState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:background_fetch/background_fetch.dart';

void main() {

// Enable integration testing with the Flutter Driver extension.
// See https://flutter.io/testing/ for more info.
runApp(new MyApp());

}

class MyApp extends StatefulWidget {

@override
_MyAppState createState() => new _MyAppState();

}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver{

@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);

print("--" + state.toString());
switch (state) {
case AppLifecycleState.inactive: // 处于这种状态的应用程序应该假设它们可能在任何时候暂停。
break;
case AppLifecycleState.resumed: // 应用程序可见,前台
break;
case AppLifecycleState.paused: // 应用程序不可见,后台
break;
case AppLifecycleState.detached: // detached
break;
}
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('前后台测试')
),

body: Container(
color: Colors.black,
child: Text('前后台测试'),
),

),

);

}

}

1、什么时候渲染完成?

使用场景:

二、路由

实践小结

[toc]

一、对比[MVC、MVP、BloC、Redux]四种架构

  • MVC、MVP、BloC、Redux四种架构在Flutter上的尝试

    对比[MVC、MVP、BloC、Redux]四种架构的好坏,

    对比[MVC、MVP、BloC、Redux]四种架构的好坏,最终还是的回归到状态管理上来。MVCMVP的状态管理都是采用setState方式,而BloCRedux都有自己的一套状态管理。

    当项目最初不是很复杂的时候,采用setState方式更新数据是可以的。但是随着功能的增加,你的项目将会有几十个甚至上百个状态,setState出现的次数便会显著增加,每次setState都会重新调用build方法,这势必对于性能以及代码的可阅读性带来一定的影响。所以就放弃了MVCMVP这两种架构。

    最初对OpenGit_Flutter进行架构重构的时候,用到的是Redux,到涉及到多个页面复用时,例如项目中的项目页,每涉及到一个复用页面就需要在state内定义一些列的变量,这是个很痛苦的过程,所以后面就放弃了用Redux,但是Redux在保存全局状态有优势,例如主题、语言、用户资料等。后面又尝试了BloC,该架构在多页面复用时,就没存在Redux的问题。

    所以最后我采用的架构是Bloc+Redux,用BloC控制局部状态,用Redux控制全局状态。

单例

Flutter中,dart的单例模式设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 创建一个单例的Manager类
class Manager {
// 工厂模式
factory Manager() =>_getInstance();
static Manager get instance => _getInstance();
static Manager _instance;
Manager._internal() {
// 初始化
}
static Manager _getInstance() {
if (_instance == null) {
_instance = new Manager._internal();
}
return _instance;
}
}

// 调用
// 无论如何初始化,取到的都是同一个对象
Manager manager = new Manager();
Manager manager2 = Manager.instance;

数据管理

shared_preferences 0.5.8

Flutter sharedPreferences使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import 'package:shared_preferences/shared_preferences.dart';

/// desc:本地储存
class SharedPreferenceUtil {
static const String UserTokenKey = "userTokenKey";

// 异步保存
Future setUserToken(String userToken) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(UserTokenKey, userToken);
}

// 异步删除
Future delUserToken() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove(UserTokenKey);
}

// 异步读取
Future<String> getUserToken() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
String userToken = prefs.getString(UserTokenKey);
print('------userToken = $userToken-----');
return userToken;
}
}



// 使用
// 保存:
SharedPreferenceUtil.setUserToken("usertoken_zhangsan");

// 读取:
Future<String> userTokenFuture = SharedPreferenceUtil.getUserToken();
userTokenFuture.then((String userToken) {
print('------userToken = $userToken-----');
});

一个不用重加载的WebView

一个不用重加载的WebView

一、背景

  • 一个基于WebView的Cocos2d游戏,因为启动加载引擎会有3-5秒的加载时长。为了更好的游戏体验,希望启动后重新进入不用重新加载。

二、webView的方案汇总

序号 描述 方式 方案 缺点
1 传统方法 页面 APage + AWebView + AWebControl 重进重载
2 单例WebControl 页面 APage + AWebView + ShareWebControl 暂未发现
3 单例WebView 页面 APage + ShareWebView Flutter因无法插入视图直接不适用
4 全局WebView 用法1 弹窗 ShareWebView 页面返回
5 全局WebView 用法2 假页面 AWebPlaceholderPage+ShareWebView 页面返回

重新梳理各方案特性:

传统方法
页面
单例WebControl
页面
单例WebView
页面
全局WebView
弹窗
全局WebView
假页面
附着物 页面 页面 页面 视图 视图
语言适用性
进出可系统控制
侧滑返回系统控制 ❌Flutter因无法插入视图直接不适用 🚗侧滑会先看到白屏
重进可免重加载 ❌重进重载

下面我们按WebView的存在形式,对WebView的方案进行各自的详细说明。

三、WebView方案之是单页面

1、传统:APage + AWebView + AControl

✅进出

✅侧滑返回

❌重进入游戏加载重复

2、webView视图”单例”—Flutter无效

🚗:Flutter因无法对视图树进行视图插入直接不适用。

不同地方共用一个webView视图()

1
2
3
APage.addSubView(shareWebView);
BPage.addSubView(shareWebView);
CPage.addSubView(shareWebView);

区别:全局webView:所有地方都使用同一个地方的webview。

3、webViewControl 单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 类似 player 的 control()
webView1.control = shareControl;
APage.addSubView(webView1);

webView2.control = shareControl;
BPage.addSubView(webView2);

webView3.control = shareControl;
CPage.addSubView(webView3)


build() {
//return shareWebView(); // ❌
return webViewWidget(control: shareControl)
}

四、WebView方案之是全局

1、直接弹窗

在Flutter上,以Overlay的方式进行全局WebView的显示时候,底部页面仍会进行相应渲染事项,即仍占用CPU、GPU。

原因:轮播图、gif动画的渲染在弹出弹窗后,并未停止。

🚄优化:显示游戏时候,轮播图停止、gif动画停止(类似隐藏游戏的时候,游戏定时器及渲染关闭)。

2、新页面+弹窗

目的:通过新页面来作为路由页。

2.1、显示方式:先显示全局webView视图,再弹出新页面

若先弹出新页面再显示全局webView视图,页面会有新页面的假白屏问题。所以,应该是先显示再弹出。

2.2、隐藏之返回方式:先关闭新页面,再隐藏全局webView视图

同理若先隐藏全局webView视图再关闭新页面,页面会有新页面的假白屏问题。所以,应该是先关闭再隐藏。

2.3、隐藏之进入新页面:直接进入新页面。

以从全局webView视图进入一个app页面。若进入新页面是先关闭全局webView视图,再进入新页面,则从新页面返回的时候,返回位置会错乱(如果为了不错乱,则你必须自己判断返回到哪)。所以应该直接进入新页面。

End

yapi的安装及其项目的创建和启动

[toc]

yapi的安装及其项目的创建和启动

官网地址:https://github.com/YMFE/yapi

前言/官网

官网 https://github.com/ymfe/yapi

一、安装yapi

使用yapi-cli 工具,部署 YApi 平台。

命令如下:

1
2
npm install -g yapi-cli --registry https://registry.npm.taobao.org	# 需要 nodejs环境
yapi server # 需要 MongoDB环境

虽然只有两个命令,但是两个命令的执行分别需要nodejs环境和MongoDB环境。

所以,使用这两个命令前,我们先按需依次完成以下步骤,搭建yapi所需的nodejs环境和MongoDB环境。

二、yapi所需环境nodejs的安装

1、nodejs环境的检测

1
node -v

如果能够执行此命令,则代表你已安装nodejs的环境,请不用再重复安装。如果没有,请看下一步3、nodejs环境的安装

2、未安装nodejs环境,导致的yapi安装失败

因为安装yapi的 npm install -g yapi-cli --registry https://registry.npm.taobao.org 那条命令,需要用到npm环境。如果没安装,则会失败如下:

image-20201117155309965

所以请先检测您电脑是否已经安装了nodejs(7.6+)了。

3、nodejs环境的安装

安装nodejs(7.6+)。另关于node的安装,请查看本网站中的node.md

三、yapi所需环境MongoDB的安装与启动

1、未配MongoDB环境,导致的yapi安装失败

执行部署yapi的 yapi server 命令时候,此时看到的执行结果如下:

yapi start1

如果你未提前安装mongodb,则会在部署yapi的时候发生如下错误。

yapi start error

所以要完成yapi的成功部署,其还需要 mongodb(2.6+)

2、MongoDB环境的检测

1
mongo -version

如果能够执行此命令,则代表你已安装mongodb的环境,请不用再重复安装。如果没有,请看3、yapi所需环境MongoDB的安装

3、yapi所需环境MongoDB的安装

方法一、可视化桌面安装

如果您是云服务器ECS,请跳过方法一,直接使用方法二终端命令安装MongoDB。

其他参考见:Mac OSX 平台安装 MongoDB

在Mac 安装MongoDB

1、点击进入下载地址https://www.mongodb.com/download-center/enterprise

mongodb download

将下载下来的tgz解压后,放到/usr/local文件夹中,并改名为mongodb

mongodb install

在改名为mongodb后,通过在终端执行open ~,找到并打开该目录下的.bash_profile中配置如下环境变量

1
export PATH=${PATH}:/usr/local/mongodb/bin

配置完后,关闭文件,终端执行如下命令,使得钢材配置的环境变量能够生效。

1
2
3
4
5
6
cd ~
source ./.bash_profile


# 或者直接下面一句
source ~/.bash_profile

不执行 上述source命令的话, mongo -version 无法生效。

安装成功后,执行mongo -version,如果不提示 command not found,代表安装成功了。

mongodb install success

至此,mongo安装完成,接下去进行启动mongo。

方法二、终端命令安装MongoDB(云服务器常用的安装方式)

Linux平台安装MongoDB官网安装文档 https://www.runoob.com/mongodb/mongodb-linux-install.html

进入地址:https://www.mongodb.com/try/download/community

image-20201117221110499

1
2
3
cd 到某个目录,执行以下命令,下载文件
yum install libcurl openssl
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-4.4.1.tgz

image-20201117235817379

1、找到并提前测试所下载的mongodb能否在本操作系统下有效执行。如果无效,会出现以下错误
1
-bash: ./mongo: cannot execute binary file: Exec format error

查看系统是几位的终端命令为getconf LONG_BIT

测试方法:

1
2
3
4
5
# 1、使用wget下载

# 2、使用tar -zxvf解压缩后

# 3、直接进入解压缩后的mongodb的bin目录下,执行对应的命令

image-20210804131852567

2、有效后,再转移并设置环境变量
1
2
3
tar -zxvf mongodb-linux-x86_64-rhel80-4.4.1.tgz

mv mongodb-linux-x86_64-rhel80-4.4.1 /usr/local/mongodb

image-20201118004346856

输入vim /etc/profile编辑环境变量文件

1
2
# set for mongo
export PATH=/usr/local/mongodb/bin:$PATH

image-20210803224610402

插入完成后,执行source /etc/profile,使环境变量生效,之后执行以下命令,就可以看到有效了。

1
mongo -version

4、yapi所需环境MongoDB的启动

命令认识:

1
2
3
4
5
6
# --dbpath 设置数据存放目录
# --logpath 设置日志存放目录
# --fork 在后台运行

# mongod --dbpath <path to data directory> # 基础的运行命令
# mongod --dbpath <path to data directory> --logpath <path to log directory> --fork # 后台的运行命令(如果要--fork,则必须有--logpath参数)

方法一:可视化桌面操作(以MacOS为例)

1、为MongoDB创建数据(必需)及日志存放的目录(可选)

步骤:为MongoDB创建数据及日志存放的目录,这里我们就把它们放在/usr/local/var目录下。

创建数据目录: /usr/local/var/mongodb

创建日志存放的目录:/usr/local/var/log/mongodb

mongodb start1

2、执行命令启动 mongodb

数据(必需)及日志存放的目录创建完成后,输入如下命令:

1
2
3
4
5
6
7
8
# --dbpath 设置数据存放目录
# --logpath 设置日志存放目录
# --fork 在后台运行
mongod --dbpath /usr/local/var/mongodb --logpath /usr/local/var/log/mongodb/mongo.log --fork


cd /usr/local/var/
mongod --dbpath ./mongodb --logpath ./log/mongodb/mongo.log --fork

mongodb start2

方法二:终端命令操作(常用于云服务器)

1、为MongoDB创建数据(必需)及日志存放的目录(可选)

步骤:为MongoDB创建数据及日志存放的目录,这里我们新建一个单独的文件夹,如CQApp-api-mongodb来单独存放yapi的数据及日志。

1
2
3
4
5
6
7
8
9
10
11
# 创建存放的目录
cd Project
mkdir CQApp-api-mongodb

# 创建数据目录data
sudo mkdir -p data
sudo chown -R 777 data

# 创建日志存放的目录log
sudo mkdir -p log
sudo chown -R 777 log

生成后,文件如下:

image-20210805014810744

2、执行命令启动 mongodb
1
2
cd Project/CQApp-api-mongodb/
mongod --dbpath ./data --logpath ./log/mongo.log --fork

image-20210805003329469

5、mongodb启动成功后,即可重新点击之前的开始部署/开始创建yapi项目。

6、yapi所需环境MongoDB的关闭

1
2
3
4
# 对于处理后台启动的mogodb的关闭,使用以下命令来关闭
pkill mongod

# 其他前台的,直接退出终端或者Ctrl+C结束就行了。

四、创建yapi项目

1、执行部署yapi的 yapi server 命令

1
yapi server

2、访问http://0.0.0.0:9090

此时看到的结果如下:

yapi start1

3、点击开始部署,

执行过程如下:

yapi start2

4、部署/创建成功

部署/创建成功,截图如下:

yapi start success

账号:admin@admin.com

密码:ymfe.org

这个账号密码,待会需要用于登录yapi网页界面使用。

此时你所填写的部署路径下,就会有所创建生成的yapi工程。

附:执行后mongodb config1

mongodb config1

五、yapi的项目运行

请查看 本博客中的yapi的项目运行.md

End

yapi的项目运行

[toc]

yapi的项目运行

官网地址:https://github.com/YMFE/yapi

一、下载已有的yapi的项目

下载你之前保存的 yapi项目:CQApp-apiyapi项目的数据:CQApp-api-mongodb两个git工程到本地云服务器ECS上,然后运行。

image-20211222150604187

二、运行效果预览

运行成功的结果:

要运行项目,最终是要进入项目,执行node vendors/server/app.js 指令启动服务器,然后在浏览器打开 http://127.0.0.1:3000 访问。

yapi start4

三、终端运行yapi项目的步骤

1、(下载并)进入yapi项目,然后启动

1.1、下载已存在的yapi项目到Project中

1
2
cd Project/
git clone https://gitee.com/dvlpApi/CQApp-api

1.2、启动yapi项目

即在终端执行的命令如下:

image-20210805012844104

如图,提示mongodb load success...则yapi启动成功。跳过如下MongoNetworkError错误,查看yapi的访问方法。

如果出现如下的MongoNetworkError问题,则原因是你执行node vendors/server/app.js 前,未先成功启动mongodb。从而导致MongoNetworkError错误。解决方式,请查看本文最后的1、MongoNetworkError的解决
MongoNetworkError

2、yapi服务开启后,我们根据提示,再在浏览器访问地址,即可看到我们的效果。

yapi start5

3、登录yapi

利用上述部署成功后的账号和密码,登录yapi网页。

账号:admin@admin.com

密码:ymfe.org # 已修改为姓名全拼

登录后的界面截图如下:

image-20201024153331339

四、如启动yapi项目过程中遇到错误,各解决方式如下

1、MongoNetworkError的解决

1.1、下载已存在的yapi项目的数据mongodb到Project中

1
2
cd Project/
git clone https://gitee.com/dvlpApi/CQApp-api-mongodb

举例:下载mongodb的问题

image-20210805001123542

1.2、启动yapi项目的数据mongodb

image-20210805003329469

这样启动mongodb后,再执行node vendors/server/app.js,就能让yapi正确启动了。

###

End

web必备基础3-代码复用

[Toc]

一、css复用

二、UI 复用

1、目前实例(jquery的load方法)

将一个页面分成多个html文件(静态html分割页面)

参考文章:

2、其他方法