Flutter系列文章-实战项目

在本篇文章中,我们将通过一个实际的 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 开发的道路上取得成功!

相关推荐
m0_748247552 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255022 小时前
前端常用算法集合
前端·算法
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203983 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2343 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1234 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~4 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语4 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport4 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg4 小时前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全