目录
- 1.页面跳转
- 2.本地数据库和读取
- 2.1 在pubspec.yaml中添加数据库框架依赖
- 2.2 创建db.dart 初始化数据库并创建表
- 2.3 安装JsonToDart插件
- 2.4 创建实体类 user_bean.dart
- 2.5 增删改查:
- 3.网络请求+数据解析+UI渲染
本篇主要总结下一个完整的Flutter项目有哪些基本构成?
一般来说数据需要展示到页面上面大概需要:
网络请求+数据解析+UI渲染、
本地数据库、
页面跳转导航等
下面一点点开始构建
1.页面跳转
创建my_routers.dart 定义Router
class MyRouter{
static const String DOWNLOAD_PAGE = "/DownLoadPage";
static const String LANG_PAGE = "/LangPage";
}
main.dart 中配置routes
class MyApp extends StatelessWidget {
final Locale locale;
const MyApp(this.locale, {super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
MyRouter.DOWNLOAD_PAGE: (context) => DownLoadPage(),
MyRouter.LANG_PAGE: (context) => LangPage(),
},
);
}
}
执行跳转
Navigator.pushNamed(context, MyRouter.DOWNLOAD_PAGE);
2.本地数据库和读取
2.1 在pubspec.yaml中添加数据库框架依赖
sqflite: ^2.3.0
(简单数据保存可用 shared_preferences: ^2.2.2
)
2.2 创建db.dart 初始化数据库并创建表
import 'package:sqflite/sqflite.dart';
//在Flutter中,创建表时可以使用以下数据类型:
//
// INTEGER:整数类型,可以存储整数值。
// REAL:浮点数类型,可以存储浮点数值。
// TEXT:文本类型,可以存储字符串值。
// BLOB:二进制类型,可以存储任意二进制数据。
// 此外,还可以使用以下修饰符来定义表中的列:
//
// PRIMARY KEY:主键修饰符,用于指定列作为主键。
// AUTOINCREMENT:自增修饰符,用于指定主键列自动增加。
// NOT NULL:非空修饰符,用于指定列的值不能为空。
// UNIQUE:唯一修饰符,用于指定列的值不能重复。
class DatabaseHelper {
static Database? _database;
//数据库名称
static const String _dbName = 'demo.db';
//数据库版本,如果表结构修改,需要增加
static const int _dbVersion = 2;
Future<Database> get database async {
if (_database != null) {
return _database!;
}
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
return await openDatabase(_dbName, version: _dbVersion,
onCreate: (db, version) async {
String studentSQL = '''
CREATE TABLE Students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER,
gpa REAL
)
''';
String userSQL = '''
CREATE TABLE User (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER
)
''';
await db.execute(userSQL);
await db.execute(studentSQL);
}, onUpgrade: (db, oldVersion, newVersion) async {
if (oldVersion == 1 && newVersion == 2) {
//修改表结构
await db.execute('ALTER TABLE User ADD sex TEXT');
}
});
}
//获取所有表
Future<List<Map<String, dynamic>>> getAllTables() async {
final Database db = await database;
return db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'");
}
// 测试
test() async {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Map<String, dynamic>> tables = await databaseHelper.getAllTables();
tables.forEach((table) {
print("当前数据中的表:${table['name']}");
});
}
}
表创建好了,该增删改查了。
2.3 安装JsonToDart插件
我们先安装一个解析json数据插件:JsonToDart
Android Studio - File - Settings - Plugins 搜索JsonToDart安装重启Android Studio即可
安装好以后创建一个Bean文件:user_bean.dart 来接收数据
2.4 创建实体类 user_bean.dart
在lib下创建bean文件夹
对着lib/bean文件夹右键 选择 new - JsonToDart 输入json数据即可生成如下文件
import 'dart:convert';
UserBean userBeanFromJson(String str) => UserBean.fromJson(json.decode(str));
String userBeanToJson(UserBean data) => json.encode(data.toJson());
class UserBean {
UserBean({
this.id,
this.name,
this.age,
});
UserBean.fromJson(dynamic json) {
id = json['id'];
name = json['name'];
age = json['age'];
}
num? id;
String? name;
num? age;
UserBean copyWith({
num? id,
String? name,
num? age,
}) =>
UserBean(
id: id ?? this.id,
name: name ?? this.name,
age: age ?? this.age,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['name'] = name;
map['age'] = age;
return map;
}
}
2.5 增删改查:
//增加
var db = await DatabaseHelper().database;
int id = await db.insert('User', userBean.toJson(),
//插入冲突策略(如果同样的对象被插入两次,则后者替换前者)
conflictAlgorithm: ConflictAlgorithm.replace);
Log.i("添加成功,id = : $id");
//删除
//where中的第一个?对应whereArgs数组的第一个
var re = await db.delete('Wallet', where: 'id = ?', whereArgs: [1]);
Log.i("删除成功 === $re");
//修改
var db = await DatabaseHelper().database;
List list = await db.query("User");
var wList = list.map((e) => UserBean.fromJson(e)).toList();
var w = wList[0];
w.name = "feifei";
var re = await db.update('User', w.toJson(),
where: 'id = ?', whereArgs: [w.id]);
Log.i("修改成功 === $re");
//查询
List list = await db.query("User");
var wList = list.map((e) => UserBean.fromJson(e)).toList();
var w = wList[0];
3.网络请求+数据解析+UI渲染
pubspec.yaml中引入依赖:
dio: ^5.3.3
创建http.dart 简单封装dio
import 'package:dio/dio.dart';
import 'app_urls.dart';
class Http {
static Dio? _dio;
static Http of({String? baseUrl}) {
return Http._initDio(baseUrl: baseUrl);
}
Http._initDio({String? baseUrl}) {
if (_dio == null) {
_dio = Dio();
Iterable<Interceptor> iterable = [
LogInterceptor(requestBody: true, responseBody: true),
];
_dio?.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 在请求被发送之前做一些事情
// 设置公共header
options.headers.addAll({'au_header': '1'});
// 设置公共参数
//options.queryParameters.addAll({'token': 'your_token'});
return handler.next(options); // 必须调用 next 方法
},
onResponse: (response, handler) {
// 在响应被处理之前做一些事情
return handler.next(response); // 必须调用 next 方法
},
onError: (DioError e, handler) {
// 在请求发生错误时做一些事情
return handler.next(e); // 必须调用 next 方法
},
));
_dio?.interceptors.addAll(iterable);
}
var options = BaseOptions(
baseUrl: baseUrl ?? AppUrls.BASE_URL,
connectTimeout: const Duration(seconds: 5),
sendTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 5),
);
_dio?.options = options;
}
//fzm-platform-id
Future<HttpResponse<dynamic>> get(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
ProgressCallback? onReceiveProgress,
}) async {
var response = await _dio!.get(path,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress);
return parse(response);
}
Future<HttpResponse<dynamic>> post(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
ProgressCallback? onReceiveProgress,
}) async {
var response = await _dio!.post(path,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress);
return parse(response);
}
}
HttpResponse parse(Response response) {
//真正的解析
var code = response.data["code"];
var data = response.data["data"];
var result = response.data["result"];
var error = response.data["error"];
if (code == 0 || code == null) {
//赋值给构造函数
return HttpResponse.success(data ?? result);
} else {
return HttpResponse.failure(error ?? "${code}");
}
}
// 注册返回:{data: null, code: -1}
class HttpResponse<T> {
bool ok = false;
T? data;
String? error;
//this.data是赋值简写
HttpResponse.success(this.data) {
ok = true;
}
//完整写法
// HttpResponse.success(T? data) {
// this.data = data;
// ok = true;
// }
HttpResponse.failure(this.error) {
ok = false;
}
}
使用dio 请求并解析渲染到UI
final List<UserBean> _userList = [];
Future<void> getExs() async {
var response = await Http.of().post("https://");
if (response.ok) {
List list = response.data;
//解析数据
List<UserBean> userList = list.map((e) => UserBean.fromJson(e)).toList();
setState(() {
_userList.addAll(userList);
});
}
}
渲染到ListView中
ListView.builder(
itemCount: _userList.length,
itemBuilder: (context, index) =>
InkWell(
onTap: (){
Navigator.pushNamed(context, MyRouter.WEB_PAGE,arguments: {
"name":_userList[index].name
});
toast(_userList[index].name??"");
},
child: Container(child: UserItem(_userList[index]))));
class UserItem extends StatelessWidget {
final UserBean userBean;
const UserItem(this.userBean, {super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 20, right: 20, top: 20),
child: Row(
children: [Text(userBean.name ?? "")],
),
);
}
}
完。