一个完整的Flutter项目的基本构成

news2024/9/21 10:55:16

目录

  • 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 ?? "")],
      ),
    );
  }
}

完。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1480342.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言第三十三弹---动态内存管理(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 动态内存管理 1、为什么要有动态内存分配 2、malloc和free 2.1、malloc 2.2、free 3、calloc和realloc 3.1、calloc 3.2、realloc 4、常见的动态内存的错…

【单片机学习的准备】

文章目录 前言一、找一个视频是二、画图软件三、装keil5 仿真protues总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 项目需要&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、找一个视频是 https://www.b…

mariadb数据库——安装,创建数据库

MariaDB是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支。 安装 apt -y install mariadb-servervi /etc/mysql/mariadb.conf.d/50-server.cnf character-set-server utf8mb4 collation-server utf8mb4_general_c…

让AI给你写代码,初体验(三)- AI加上格式化对话,实现对单个文件的修改/保存

上一篇中&#xff0c;AI生成web应用初步解决了简单web应用生成&#xff0c;但是存在两方面的问题 1&#xff09; 无法向AI提供增量需求&#xff0c;特别是一个对话结束之后&#xff0c;只能把全部需求&#xff08;包括新需求&#xff09;再描述一遍 2&#xff09; 无法用AI对存…

深入学习NumPy库在数据分析中的应用场景

在数据科学与机器学习领域&#xff0c;NumPy&#xff08;Numerical Python&#xff09;是一个经常被提及的重要工具。它是Python语言中一个非常强大的库&#xff0c;提供了高性能的多维数组对象以及用于处理这些数组的工具。NumPy不仅仅是一个用于数值计算的库&#xff0c;它还…

Redis第6讲——主从复制模式详解

Redis的读写性能很高&#xff0c;但在面对大规模数据和高发访问的挑战时&#xff0c;单节点的Redis可能无法满足需求&#xff0c;这就引出了Redis集群的概念。本节先介绍一下Redis高可用方案之一的主从复制模式&#xff0c;虽说现在基本不会用这种模式&#xff0c;但是无论是哨…

Web自动化测试平台开发---Automated_platform

一、项目简介 历时一个假期&#xff0c;Automated_platform 第一版完工&#xff0c;是一款基于po模式的自动化测试平台,采用后端技术为DjangoceleryRabbitMQmysql 配置mysql数据库&#xff0c;进行数据迁移后&#xff0c;运行项目后&#xff0c;即可成功访问http://127.0.0.1:8…

单调栈的理解

单调栈的理解 核心代码场景思考 完整代码 单调栈&#xff1a; 单调递增或 单调递减的栈 核心代码 while (!s.empty()&&s.peek()<nums[i]){s.pop(); } s.push(nums[i]);将要放入的元素&#xff0c;与栈内元素依个比较&#xff0c;小于的都出栈&#xff0c;最后将要…

List 集合遍历过程中删除元素避坑指南。

文章目录 1. 遍历2. 遍历过程中删除元素2.1 for 简单循环正向遍历方式2.2 for 简单循环反向遍历方式2.3 foreach 方式遍历删除2.4 Iterator的remove()方法2.5 <font color green> removeIf() &#xff08;推荐&#xff09;<green>2.6 Strem 方式 作为一名后端开发…

Executable and Linkable Format(ELF)

File layout ELF文件有两种视图。程序头表&#xff08;Program Header&#xff09;显示在运行时使用的段&#xff08;Segments&#xff09;&#xff0c;而节头表&#xff08;Section Header&#xff09;则列出了二进制文件的所有节&#xff08;Sections&#xff09;的集合。程…

SCT2633STER:4.5V-60V Vin,3A,高效降压DCDC转换器

•宽输入范围&#xff1a;4.5V-60V •高达3A的连续输出电流 •1.221V1%反馈参考电压 •集成220mΩ高压侧MOSFET •低静态电流为300uA •轻负载下的脉冲跳过模式&#xff08;PSM&#xff09; •最小接通时间100ns •内置12ms软启动时间 •简易内部补偿 •固定频率500KH…

使用Docker搭建一款实用的个人IT工具箱——It-Tools

作为程序员&#xff0c;在日常工作中&#xff0c;需要借助一些工具来提高我们工作效率&#xff0c;IT-Tools是为开发人员度身打造的一套便捷在线工具。它提供全面功能&#xff0c;使开发者能以更高效方式完成任务。经由IT-Tools&#xff0c;开发人员能轻松应对各类技术挑战&…

怎么抠图把把人物扣下来?简单快捷的抠图方法

相信很多新手小白在初入设计行业时&#xff0c;对于抠图怎么把人物扣下来都是一头雾水。抠图作为设计中常用的一种技术&#xff0c;能够帮助我们快速提取图片中的某个部分&#xff0c;进行合成或者修改。对于老手来说&#xff0c;抠图或许是再熟悉不过的操作&#xff0c;但对于…

WPF中如何设置自定义控件

1.圆角按钮的设置&#xff1a; 众所周知在WPF中自带有提示信息&#xff0c;当我问创建Button时&#xff0c;点击空格出现如下可选设置 带有小扳手&#x1f527;图标为相应的属性&#xff0c;如果Button有CornerRadius&#xff08;角半径&#xff09;属性就能够直接设置Button实…

Unity中URP实现水体(整理优化)

文章目录 前言一、优化水的深度1、我们把 水流动的方向 和 水深浅过渡值&#xff0c;整合到一个四维变量中2、修改 水体流动方向3、在片元着色器中&#xff0c;修改使用过渡变量 二、优化泡沫三、优化水下的扭曲1、修复原本扰动UV的计算 四、优化水面高光1、把高光强度、光滑度…

如何用ai智能写作?推荐5款优秀的AI写作神器

写作是件繁琐的事情&#xff0c;也是需要耗费精力和时间的&#xff0c;还好目前有了ai写作神器的出现&#xff0c;帮助我们解决了不少的写作难题。这些AI写作工具不仅可以帮助我们提高写作效率&#xff0c;还能够生成高质量的内容。在本文中&#xff0c;我将向你推荐5款优秀的A…

MATLAB中strel函数用法

目录 语法 说明 任意邻域形状 二维几何邻域形状 三维几何邻域形状 示例 创建正方形结构元素 创建线形结构元素 创建盘形结构元素 创建三维球形结构元素 参数说明 属性 strel函数的功能是形态学结构元素。 语法 SE strel(nhood) SE strel("diamond",r…

BUUCTF AWD-Test1

打开靶场是这个有些简陋的界面。 随便点点&#xff0c;找到这个东西。 看到ThinkPHP&#xff0c;思路瞬间清晰&#xff0c;老熟人了。这个就是ThinkPHP漏洞。根据版本我们去找一下poc。 /index.php/?sIndex/\think\View/display&content%22%3C?%3E%3C?php%20phpinfo();…

Git工具Clone项目报错:OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054

目录 问题现象&#xff1a; 解决方法&#xff1a; 问题现象&#xff1a; 今天在项目中使用git工具clone远程库的项目地址时&#xff0c;遇到了如下报错&#xff0c;导致无法克隆项目代码到本地&#xff1a; OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054 解决方法&#…

【从Python基础到深度学习】9.Python 语法基础

一、常量与变量 常量:程序中使用的具体的数、字符。在运行过程中&#xff0c;值无法更改 变量:表示一一个存储单元&#xff0c;其中存储的值可以修改 如&#xff1a;a5,b6 变量命名: 1、只能包含字母、数字、下划线 2、只能以字母、下划线开头 3、不要使用关键字作为变量名称 …