大数跨境

Flutter多端开发快速入门、Flutter基于AI开发时的注意事项

Flutter多端开发快速入门、Flutter基于AI开发时的注意事项 锐英源软件
2026-08-24
0
导读:Flutter多端开发快速入门和Flutter基于AI开发时的注意事项,项目架构说明,代码详细解释,适合各类层次朋友共同提高。Flutter多端开发能力在牛身App里有体现,在Windows下可运行,

背景

前几天,我需要开发手机App,AI推荐了Flutter,并快速生成了代码,连接FastAPI接口,获取数据,绘制结果,花了200左右的积分,迅速完成。AI还贴心地生成了手机拍照功能,拍照照片上传到FastAPI服务器上。现在普遍对AI生成代码不太放心,这里强调两点FastAPI的安装部署和运行,Flutter的内存泄漏问题,不是说Flutter会轻易内存泄漏,Flutter是成熟的平台,我只是说从某个点来讲内存泄漏,让普通程序员和新手怎么查泄漏,有谨慎心态能落地实践。

Dart是Google开发的⼀种面向对象的计算机编程语言,和Java类似。Flutter是Google开源的UI⼯具包,帮助开发者通过⼀套代码库高效构建多平台精美应用,支持移动、Web、桌面和嵌入式平台。 Dart是flutter的程序开发语言。Flutter能被AI推荐,有大量的QQ群,群里有很多爱好者,都证明Flutter的成功。Flutter多端就是Flutter多平台的意思,移动、Web、桌面和嵌入式平台都可以用Flutter开发,所以叫Flutter多端。这里面最重要的是苹果的iOS开发,xcode需要运行在iOS下,一般是用虚拟机来做,环境不太有好。Flutter的一次开发,多端(多平台)兼容,会节省很多时间。如果不用Flutter,需要掌握多门编程语言和多个开发环境,工作量大。


Flutter项目的具体架构

# 牛身检测 Flutter App

一个简单的Flutter应用,用于上传牛只图片并显示检测到的牛身轮廓。

## 项目结构

```
cowapp/
├── lib/
│ ├── main.dart # 应用入口
│ ├── home_page.dart # 主页面(按钮+图片控件)
│ ├── services/
│ │ └── api_service.dart # API服务(与后端通信)
│ └── widgets/
│ └── contour_painter.dart # 轮廓绘制组件
├── pubspec.yaml # 项目配置
└── README.md # 本文件
```

## 功能

1. 点击按钮从图库选择牛只图片
2. 自动上传到后端服务器进行检测
3. 显示检测到的牛身轮廓(绿色线条)
4. 在原图上叠加显示轮廓结果

## 技术栈

- **Flutter**: 前端框架
- **image_picker**: 图片选择
- **http**: 网络请求
- **CustomPainter**: 轮廓绘制

## 运行步骤

### 1. 启动后端服务

```bash
cd d:\cow
python server.py
```

服务将在 `http://localhost:8000` 启动。

### 2. 安装Flutter依赖

```bash
cd d:\cowapp
flutter pub get
```

### 3. 运行Flutter应用

```bash
flutter run
```

## API接口

### POST /view_body_new_service

**请求**:
- Content-Type: multipart/form-data
- Body: 图片文件(字段名: file)

**响应**:
```json
{
"success": true,
"message": "检测成功",
"contour_points": [[x1,y1], [x2,y2], ...],
"image_width": 4096,
"image_height": 3072
}
```

## 注意事项

1. **后端服务地址**: 默认连接到 `http://localhost:8000`,可在 `api_service.dart` 中修改

2. **图片大小**: 支持最大4096x3072分辨率,会自动缩放显示

3. **轮廓绘制**: 使用绿色线条绘制,红色圆点标记起点

4. **缩放处理**: CustomPainter 会根据原图尺寸和显示尺寸自动计算缩放比例,确保轮廓点正确对齐

## 待优化功能

- [ ] 添加进度显示
- [ ] 支持相机拍照
- [ ] 显示更多检测信息(如牛身特征)
- [ ] 支持多张图片批量处理
- [ ] 离线模式缓存

 

Flutter多端开发能力在这个牛身App里有体现,在Windows下可以运行,编译成apk就可以在安卓手机上运行,在Windows下功能测试完成,则安卓手机上的测试就相对简单多了。

 

contour_painter.dart轮廓绘制组件代码解析和内存泄漏分析

import 'package:flutter/material.dart';//导入库 import 'package:flutter/foundation.dart';  class ContourPainter extends CustomPainter {   final List<List<int>> contourPoints;//坐标数组   final int imageWidth;   final int imageHeight;   final Color contourColor;   final double strokeWidth;    ContourPainter({     required this.contourPoints,     required this.imageWidth,     required this.imageHeight,     this.contourColor = Colors.green,     this.strokeWidth = 3.0,   });    @override   void paint(Canvas canvas, Size size) {//重写的绘制函数     if (kDebugMode) {       print('[ContourPainter] paint 被调用');       print('[ContourPainter] 画布尺寸: ${size.width}x${size.height}');       print('[ContourPainter] 原图尺寸: ${imageWidth}x$imageHeight');       print('[ContourPainter] 轮廓点数: ${contourPoints.length}');       if (contourPoints.isNotEmpty) {         print('[ContourPainter] 第一个点: ${contourPoints.first}');         print('[ContourPainter] 最后一个点: ${contourPoints.last}');       }     }      if (contourPoints.isEmpty || imageWidth == 0 || imageHeight == 0) {       if (kDebugMode) {         print('[ContourPainter] 提前返回(数据为空)');       }       return;     }      // 现在外层 FittedBox 统一缩放,画布 size 应等于原图像素尺寸     // 这里仍然计算一个 scale 以防御不一致情况     final scaleX = size.width / imageWidth;     final scaleY = size.height / imageHeight;     final scale = (scaleX > 0 && scaleY > 0)         ? scaleX // 正常情况下 scaleX == scaleY == 1.0(因为 FittedBox)         : 1.0;      if (kDebugMode) {       print('[ContourPainter] scaleX=$scaleX, scaleY=$scaleY, scale=$scale');     }      // 创建画笔     final paint = Paint()       ..color = contourColor       ..strokeWidth = strokeWidth // 直接使用像素线宽,FittedBox会整体缩放       ..style = PaintingStyle.stroke       ..strokeCap = StrokeCap.round       ..strokeJoin = StrokeJoin.round;      // 绘制轮廓路径     if (contourPoints.length > 1) {       final path = Path();        // 移动到第一个点       final startX = contourPoints[0][0] * scale;       final startY = contourPoints[0][1] * scale;       path.moveTo(startX, startY);        if (kDebugMode) {         print('[ContourPainter] 路径起点: ($startX, $startY)');       }        // 连接所有轮廓点       for (int i = 1; i < contourPoints.length; i++) {         final x = contourPoints[i][0] * scale;         final y = contourPoints[i][1] * scale;         path.lineTo(x, y);       }        // 闭合路径       path.close();        // 绘制路径       canvas.drawPath(path, paint);       if (kDebugMode) {         print('[ContourPainter] 路径已绘制');       }     }      // 绘制起点标记(红色圆点)     if (contourPoints.isNotEmpty) {       final startX = contourPoints[0][0] * scale;       final startY = contourPoints[0][1] * scale;        final startPaint = Paint()         ..color = Colors.red         ..style = PaintingStyle.fill;        canvas.drawCircle(         Offset(startX, startY),         6.0, // 固定像素大小,外层会缩放         startPaint,       );     }      // 绘制所有轮廓点(小圆点),间隔绘制避免太密集     final pointPaint = Paint()       ..color = contourColor.withValues(alpha: 0.6)       ..style = PaintingStyle.fill;      for (int i = 0; i < contourPoints.length; i++) {       if (i % 5 == 0) {         final x = contourPoints[i][0] * scale;         final y = contourPoints[i][1] * scale;         canvas.drawCircle(           Offset(x, y),           2.0,           pointPaint,         );       }     }   }    @override   bool shouldRepaint(covariant ContourPainter oldDelegate) {//重写的触发绘制函数     // 当轮廓点、颜色、线宽、图片尺寸变化时重绘     return oldDelegate.contourPoints != contourPoints ||         oldDelegate.contourColor != contourColor ||         oldDelegate.strokeWidth != strokeWidth ||         oldDelegate.imageWidth != imageWidth ||         oldDelegate.imageHeight != imageHeight;   } }

dart语言类似Java,当然也像C#,这里面没有指针,使用还是很方便。这里面Path()是常用的资源对象,资源对象用不好会导致内存泄漏。Flutter在频繁分配Path()时会出问题,但是这些代码明显是不频繁的,是可以接受的。为什么不频繁?paint绘制的前提是数据对象改变让shouldRepaint返回真,才绘制,不频繁绘制就不会分配Path()对象,所以代码是正确的。其它的对象不涉及内存泄漏。


【声明】内容源于网络
0
0
锐英源软件
1234
内容 43
粉丝 0
锐英源软件 1234
总阅读32
粉丝0
内容43