目录
- 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.@overrideWidget 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) {// 在请求被发送之前做一些事情// 设置公共headeroptions.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-idFuture<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});@overrideWidget build(BuildContext context) {return Container(padding: EdgeInsets.only(left: 20, right: 20, top: 20),child: Row(children: [Text(userBean.name ?? "")],),);}
}
完。