在本篇文章中,我们将通过一个实际的 Flutter 应用来综合运用最近学到的知识,包括保存到数据库、进行 HTTP 请求等。我们将开发一个简单的天气应用,可以根据用户输入的城市名获取该城市的天气信息,并将用户查询的城市列表保存到本地数据库中。

第一步:需求分析和设计

1. 确定项目目标

我们的目标是开发一个天气应用,用户可以在应用中输入城市名,然后获取该城市的天气信息。

2. 设计界面

我们的应用包含两个页面:主页面用于输入城市名,显示天气信息,以及查询历史记录页面用于显示用户查询的城市列表。

第二步:开发

1. 创建 Flutter 项目

首先,在命令行中创建一个新的 Flutter 项目:

flutter create my_first_flutter_app

然后,进入项目目录:

cd my_first_flutter_app

2. 编码实现

a. 创建页面和路由

在 lib 文件夹中创建两个文件:home_page.dart、history_page.dart。

home_page.dart:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert'; class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
} class _HomePageState extends State<HomePage> {
String city = '';
String weather = ''; void getWeather() async {
final response = await http.get(Uri.parse(
'https://api.openweathermap.org/data/2.5/weather?q=$city&appid=YOUY_API_KEY')); if (response.statusCode == 200) {
final data = jsonDecode(response.body);
setState(() {
weather =
'Temperature: ${data['main']['temp']}°C, Weather: ${data['weather'][0]['main']}';
});
} else {
setState(() {
weather = 'Failed to get weather data';
});
}
} @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Weather App'),
),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
onChanged: (value) {
setState(() {
city = value;
});
},
decoration: InputDecoration(labelText: 'City Name'),
),
ElevatedButton(
onPressed: () {
getWeather();
},
child: Text('Get Weather'),
),
SizedBox(height: 20),
Text(
weather,
style: TextStyle(fontSize: 18),
),
],
),
),
);
}
}

history_page.dart:

import 'package:flutter/material.dart';
import 'package:my_first_flutter_app/database_helper.dart';
import 'package:my_first_flutter_app/city.dart'; class HistoryPage extends StatefulWidget {
@override
_HistoryPageState createState() => _HistoryPageState();
} class _HistoryPageState extends State<HistoryPage> {
List<City> cities = []; @override
void initState() {
super.initState();
fetchCities();
} void fetchCities() async {
final dbHelper = DatabaseHelper.instance;
final allRows = await dbHelper.queryAllRows();
setState(() {
cities = allRows.map((row) => City.fromMap(row)).toList();
});
} @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Search History'),
),
body: ListView.builder(
itemCount: cities.length,
itemBuilder: (context, index) {
final city = cities[index];
return ListTile(
title: Text(city.name),
subtitle: Text('Weather: ${city.weather}'),
);
},
),
);
}
}

在 main.dart 文件中,设置路由:

import 'package:flutter/material.dart';
import 'package:my_first_flutter_app/home_page.dart';
import 'package:my_first_flutter_app/history_page.dart'; void main() {
runApp(MyApp());
} class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/history': (context) => HistoryPage(),
},
);
}
}

b. 实现数据库功能

我们将使用 SQLite 来保存用户查询的城市列表。在 lib 文件夹中创建新的文件 city.dart、database_helper.dart,用于创建和管理数据库。

city.dart

class City {
int id;
String name;
String weather; City({this.id = 0, required this.name, required this.weather}); Map<String, dynamic> toMap() {
return {'id': id, 'name': name, 'weather': weather};
} City.fromMap(Map<String, dynamic> map)
: id = map['id'],
name = map['name'],
weather = map['weather'];
}

database_helper.dart

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'package:my_first_flutter_app/city.dart'; class DatabaseHelper {
static final _databaseName = 'weather_database.db';
static final _databaseVersion = 1; static final table = 'cities'; static final columnId = '_id';
static final columnName = 'name';
static final columnWeather = 'weather'; DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor(); static Database? _database;
Future<Database?> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
} _initDatabase() async {
String path = join(await getDatabasesPath(), _databaseName);
return await openDatabase(path,
version: _databaseVersion, onCreate: _onCreate);
} Future<void> _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$columnName TEXT NOT NULL,
$columnWeather TEXT NOT NULL
)
''');
} Future<int> insert(City city) async {
Database? db = await instance.database;
return await db?.insert(table, city.toMap()) ?? 0;
} Future<List<Map<String, dynamic>>> queryAllRows() async {
Database? db = await instance.database;
return await db?.query(table) ?? [];
}
}

第三步:测试

1. 运行应用

使用以下命令在模拟器或真机上运行应用:

flutter run

检查应用是否按预期工作,并确保你可以查询城市的天气,并查看查询历史记录。

2. 进行单元测试和集成测试

除了手动测试之外,我们还应该进行单元测试和集成测试来确保应用的稳定性和正确性。在 Flutter 中,我们可以使用 flutter_test 包进行测试。

第四步:发布

当我们完成了开发和测试之后,就可以考虑发布应用了。在发布之前,我们需要完成以下几个步骤:

1. 生成 APK 或 IPA 文件

使用以下命令生成 APK 文件(Android)或 IPA 文件(iOS):

flutter build apk
flutter build ios

2. 申请开发者账号

如果你要发布到应用商店(如 Google Play 或 App Store),你需要申请开发者账号,并遵循相应的发布指南。

3. 提交应用

一旦你准备好了 APK 或 IPA 文件,并且已经申请了开发者账号,你可以提交应用到相应的应用商店进行审核和发布。

总结

在本篇文章中,我们通过一个简单的天气应用示例,综合运用了最近学到的知识,包括保存到数据库、进行 HTTP 请求等。通过这个实战项目,你可以更加深入地了解 Flutter 应用的开发流程,并掌握实际项目中的常用技术和最佳实践。

希望这个实战项目对你有所帮助。如果你有任何问题或需要进一步的指导,请随时向我询问。祝你在 Flutter 开发的道路上取得成功!

本文由mdnice多平台发布

Flutter系列文章-实战项目的更多相关文章

  1. nginx高性能WEB服务器系列之五--实战项目线上nginx多站点配置

    nginx系列友情链接:nginx高性能WEB服务器系列之一简介及安装https://www.cnblogs.com/maxtgood/p/9597596.htmlnginx高性能WEB服务器系列之二 ...

  2. 一、VUE项目BaseCms系列文章:项目介绍与环境配置

    一.项目效果图预览: 二.项目介绍 基于 elementui 写一个自己的管理后台.这个系列文章的目的就是记录自己搭建整个管理后台的过程,希望能帮助到那些入门 vue + elementui 开发的小 ...

  3. 我的.net并发系列文章及项目经验整理

    一直在关注研究.net下的并发处理,之前也发布过几篇文章,今天就都整理下. 使用BlockingCollection来做并发处理,同时增加并发队列来做并发处理时的退出判断: 你真的知道.NET Fra ...

  4. 二、VUE项目BaseCms系列文章:项目目录结构介绍

    一. 目录结构截图 二. 目录结构说明 - documents    存放项目相关的文档文件 - api   api 数据接口目录 - assets    资源文件目录 - components   ...

  5. 【Flutter 实战】17篇动画系列文章带你走进自定义动画

    老孟导读:Flutter 动画系列文章分为三部分:基础原理和核心概念.系统动画组件.8篇自定义动画案例,共17篇. 动画核心概念 在开发App的过程中,自定义动画必不可少,Flutter 中想要自定义 ...

  6. 开篇:软件项目的整个流程 - IT软件人员学习系列文章

    这段时间闲来无事,就在总结以前的项目经验,然后写成博客的形式以进行记录.本文就对<IT软件人员学习系列文章>做个开篇吧. 对于IT软件的开发来说,无外乎B/S.C/S和Android.iO ...

  7. Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...

  8. QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL

    QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL 课程1   C语言程序设计高级实用速成课程 基础+进阶+自学 课程2   C语言程序设计Windows GDI图形绘 ...

  9. Rancher 系列文章-Rancher 对接 Active Directory 实战

    概述 只要是个公司,基本上都有邮箱和 AD(Active Directory). 在 AD 里,已经有了: 用户 账号密码 邮箱 用户组 组织架构 所以对于一些仅限于本公司一定范围内人员使用的管理或后 ...

  10. Velero系列文章(四):使用Velero进行生产迁移实战

    概述 目的 通过 velero 工具, 实现以下整体目标: 特定 namespace 在B A两个集群间做迁移; 具体目标为: 在B A集群上创建 velero (包括 restic ) 备份 B集群 ...

随机推荐

  1. 聚合短信PHP代码示例短信接口调用CURL方法

    聚合的短信相信大家已经做多了吧,网上的代码看了下就是感觉太繁琐了,不过网上的也是比较好的,用的是post方法,更安全,因我们的项目是在服务器上请求,又绑定了白名单 ,所以弄了个简单点的自己用,参考如下 ...

  2. 2021-11-11:打乱数组。给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。实现 Solution class:Solutio(int[] nums) 使用整数数组 nums

    2021-11-11:打乱数组.给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组.实现 Solution class:Solutio(int[] nums) 使用整数数组 nums ...

  3. 给你安利一款国产良心软件uTools

    前言 大家好,我是xiezhr 最近由于换了新电脑,也是在各种折腾搭建开发环境,安装各种常用软件.今天呢给大家安利一款你可能没用过的国产良心软件uTools,这也是我刚刚拿到电脑后安装的第一款软件吧. ...

  4. ClickHouse笔记: Ubuntu/Centos下的安装, 配置和用户管理

    ClickHouse ClickHouse 属于 OLAP 数据库 OLTP 与 OLAP OLTP (On-Line Transaction Processing 联机事务处理), 注重事务处理, ...

  5. vue全家桶进阶之路43:Vue3 Element Plus el-form表单组件

    在 Element Plus 中,el-form 是一个表单组件,用于创建表单以便用户填写和提交数据.它提供了许多内置的验证规则和验证方法,使表单验证更加容易. 使用 el-form 组件,您可以将表 ...

  6. 让ChatGPT帮我写SQL

    推荐一个Github上Start超过3.4K,可将自然语言转化为SQL语句的开源项目. 项目简介 这是一个利用ChatGPT,SQL与自然语言的翻译器.可以将自然语言转换为SQL语句,同样也可以把SQ ...

  7. Golang 协程/线程/进程 区别以及 GMP 详解

    Golang 协程/线程/进程 区别详解 转载请注明来源:https://janrs.com/mffp 概念 进程 每个进程都有自己的独立内存空间,拥有自己独立的地址空间.独立的堆和栈,既不共享堆,亦 ...

  8. Linux服务器设置虚拟内存

    cd /usrsudo mkdir swapcd swapsudo dd if=/dev/zero of=/usr/swap/swapfile bs=1M count=4096du -sh /usr/ ...

  9. 浅谈 thinkphp composer 扩展包加载原理

    浅谈 thinkphp composer 扩展包加载原理 本文将介绍 ThinkPHP 中 Composer 扩展包的加载原理,帮助读者更好地理解和应用该功能. 前言 如题,今天感觉好久没有更新博客了 ...

  10. 【C++ Primer】2.1 基本内置类型

    1. 基本内置类型 基本算数类型: 类型 含义 最小尺寸 bool 布尔类型 8bits char 字符 8bits wchar_t 宽字符 16bits char16_t Unicode字符 16b ...