在本篇文章中,我们将通过一个实际的 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. 【STL】C++使用STL处理替换字符串操作。

    // Examples4STL.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <stdio.h> #incl ...

  2. cat,more,cp,mv,rm,命令

    cat命令 查看文件内容 语法:cat[linux路径] more命令查看文件内容 more命令同样可以查看文件内容, 同cat不同的是: •cat是直接将内容全部显示出来 •more支持翻页,如果文 ...

  3. 2022-07-17:1、2、3...n-1、n、n、n+1、n+2... 在这个序列中,只有一个数字有重复(n)。 这个序列是无序的,找到重复数字n。 这个序列是有序的,找到重复数字n。

    2022-07-17:1.2.3-n-1.n.n.n+1.n+2- 在这个序列中,只有一个数字有重复(n). 这个序列是无序的,找到重复数字n. 这个序列是有序的,找到重复数字n. 答案2022-07 ...

  4. 2020-11-24:n个物品每个物品都有一定价值,分给2个人,怎么分两个人的价值差最小?

    福哥答案2020-11-24: 背包问题:背包容量是SUM/2. 每个物体的体积是数的大小,然后尽可能的装满背包. golang代码如下: package main import ( "fm ...

  5. Luogu1772 [ZJOI2006] 物流运输

    传送门 简化题意 给你 \(m\) 个码头,码头之间有双向边连接,\(n\) 天,其中一些码头在某些天会不可用,这 \(n\) 天都要有一条从 \(1\) 到 \(m\) 的路,每一次更换道路会需要 ...

  6. vue 中render执行流程梳理

    用了多年vue 今天对自己了解的render 做一个梳理 一.使用template模板 先从vue 初始化开始: 众所周知项目的main.js中定义了 var app = new Vue({})这vu ...

  7. javaer你还在手写分表分库?来看看这个框架怎么做的 干货满满

    java orm框架easy-query分库分表之分表 高并发三驾马车:分库分表.MQ.缓存.今天给大家带来的就是分库分表的干货解决方案,哪怕你不用我的框架也可以从中听到不一样的结局方案和实现. 一款 ...

  8. .Net8罕见的技术:MSIL的机器码简析

    前言 一般的只有最终的汇编代码才有机器码表示,然一个偶然的机会发现,MSIL(Microsoft intermediate language)作为一个中间语言表示,居然也有机器码,其实这也难怪,计算机 ...

  9. 驱动开发:内核ShellCode线程注入

    还记得<驱动开发:内核LoadLibrary实现DLL注入>中所使用的注入技术吗,我们通过RtlCreateUserThread函数调用实现了注入DLL到应用层并执行,本章将继续探索一个简 ...

  10. MySQL锁表解锁表

    CREATE TABLE t1 ( id int(11) NOT NULL, val varchar(10) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoD ...