山大迷踪移动日志1

对数据库sqflite的封装

因为要临时存储用户登录状态,存储token等等的需求,所以把基本的很繁琐的数据库操作封装到DBManager和DBProvider,两个类中。具体的数据库操作对象只需要继承DBProvider类,然后自定义增删改查的函数即可。

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
class DBManager{
static const int _VERSION = 1;
static const String _DB_NAME = 'isdu.db';
static Database? _database;
static init() async {
var dbPath = await getDatabasesPath();
String dbName = _DB_NAME;
String path = dbPath + dbName;
if(Platform.isIOS){
path = dbPath + "/" + dbName;
}
_database = await openDatabase(
path,
onCreate: (Database db,int version) async {
},
version: _VERSION,
);
}
static isTableExists(String tableName) async {
await getCurrentDatabase();
String sql =
"select * from Sqlite_master where type = 'table' and name = '$tableName'";
var res = await _database?.rawQuery(sql);
return res != null && res.isNotEmpty;
}
static Future<Database?> getCurrentDatabase() async {
if(_database == null) {
await init();
}
return _database;
}
static close(){
_database?.close();
_database = null;
}
}
abstract class DBProvider{
bool isTableExits = false;
tableSqlString();
tableName();
Future<Database> getDatabase() async {
return await open();
}
@mustCallSuper
prepare(name, String createSql) async {
isTableExits = await DBManager.isTableExists(name);
if(!isTableExits){
Database? db = await DBManager.getCurrentDatabase();
return await db?.execute(createSql);
}
}
@mustCallSuper
open() async {
if(!isTableExits){
await prepare(tableName(), tableSqlString());
}
return await DBManager.getCurrentDatabase();
}
}

之后,使用DBProvider即可构建所需的dao。例:

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
class LoginDao extends DBProvider{
final String name = "loginCheck";
final String columnId = 'id';

@override
tableName() => name;

@override
tableSqlString() {
return 'create table $name ($columnId integer primary key autoincrement,isLogin INTEGER)';
}

Future insert(LoginCheck loginCheck) async {
Database db = await getDatabase();
return await db.insert(name, loginCheck.toMap());
}
Future update(LoginCheck loginCheck) async {
Database db = await getDatabase();
return await db.update(name,loginCheck.toMap(),where: 'id = ?',whereArgs: ['1']);
}
Future<LoginCheck?> query(String id) async {
Database db = await getDatabase();
List<Map<String,dynamic>> maps =
await db.query(name,where: "id = ?",whereArgs: [id]);
if(maps.isNotEmpty){
LoginCheck loginCheck = LoginCheck.fromMap(maps.first);
return loginCheck;
}
return null;
}
}

在页面初始化时使用异步

有时候需要在页面构建之前进行一次异步操作(是不是可以说我们无法真正的在构建之前进行异步操作),其实异步内的内容是到最后才去执行的。

踩坑一

image-20220720203447362

原因:在执行build()之前,super.initState()没有得到执行。

踩坑二

image-20220720203511266

结果:_load()没有在构建页面之前执行

原因:异步嘛~

顺便一提,看到网上还有人这么写

1
2
3
4
5
6
7
8
9
10
11
12
  _load() async {
await ...
}

@override
void initState (){
super.initState();
Future.delayed(Duration.zero, () => setState(() {
   _load();
}));
}

嗯……是sleep()的味道呢

解决方案:

最终的解决方案嘛,也不能说很完美。大体思路就是,先设一个初始值,让页面第一次构建的时候使用这个值;等到拿到回调的结果后,再赋新值,同时setState()刷新。

此时,初始值很关键。大概就是第一次使用时连续闪出两个页面(第一个太快看不见,只能看到第二个),之后无影响和第一次无违和感,之后每次都闪一下的区别。

image-20220720205144139

response转map

使用dio获得的response对象的data.toString()是这样的

{code: 0, message: success, data: [6afe0c0544625b5204b2588f9021adc5, 0b49ef4b6388c3303082800980b6bca4]}

也就是说,没有引号而且在奇怪的地方有空格,无法通过json转成map

需要经过下面的操作

1
2
3
4
5
6
7
s = s.replaceAll(" ", "");
s = s.replaceAll("{", "{\"");
s = s.replaceAll(":", "\":\"");
s = s.replaceAll(",", "\",\"");
s = s.replaceAll("}", "\"}");
s = s.replaceAll("\"[", "[\"");
s = s.replaceAll("]\"", "\"]");

画UI

appbar的颜色

一般颜色可以改

1
2
3
ThemeData(
primarySwatch: Colors.xxx,
),

但不能是Colors.white或Colors.black,因为它们不被认为是MaterialColor,此外也不能使用自定义的颜色,但是我们可以通过自定义一个产生MaterialColor的函数来自定义主题色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MaterialColor createMaterialColor(Color color) {
List strengths = <double>[.05];
Map<int, Color> swatch = {};
final int r = color.red, g = color.green, b = color.blue;
for (int i = 1; i < 10; i++) {
strengths.add(0.1 * i);
}
strengths.forEach((strength) {
final double ds = 0.5 - strength;
swatch[(strength * 1000).round()] = Color.fromRGBO(
r + ((ds < 0 ? r : (255 - r)) * ds).round(),
g + ((ds < 0 ? g : (255 - g)) * ds).round(),
b + ((ds < 0 ? b : (255 - b)) * ds).round(),
1,
);
});
return MaterialColor(color.value, swatch);
}

这样就可以写成下面这种形式

1
2
3
ThemeData(
primarySwatch: createMaterialColor(Color(0x9c0c13)),//山大红
),
1
2
3
4
5
6
7
8
9
{
"code":"1",
"msg":"操作成功",
"data":
{
"nickName":"null",
"name":"lhs","isAdmin":"false","avatar":"null"},
"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI0IiwiZXhwIjoxNjU5NDk4MDc3LCJpbmZvIjp7InBhc3N3b3JkIjoicmV0dXJuMDsiLCJzaWQiOiIyMDIxMDAzMDAyMDkifX0.TRHfkKYd5couo6otPryU9WLOEo7aaQOIq5OuqANVEok"
}

StaggeredGridView弃用了


山大迷踪移动日志1
http://halfatooth.github.io/2022/07/22/sdu-adventure-1/
作者
lhs
发布于
2022年7月22日
许可协议