Flutter for OpenHarmony:迈向专业:购物APP的架构演进与未来蓝图

Flutter for OpenHarmony:迈向专业:购物APP的架构演进与未来蓝图

引言

经过前两篇文章的努力,我们的"淘淘购物"APP已经具备了基本的形态和交互能力。然而,审视当前的代码,我们会发现一些潜在的隐患:数据硬编码在UI文件中、状态管理逻辑与UI紧密耦合、缺乏对网络请求和持久化存储的支持。这些问题在小型Demo中或许无伤大雅,但在一个真实的、需要长期维护和迭代的商业项目中,它们将成为巨大的技术债务。

本文将作为本系列的收官之作,带领大家跳出代码细节,从更高的维度思考应用的架构设计。我们将对现有代码进行一次彻底的重构,引入清晰的分层架构,并探讨如何集成现代Flutter开发的最佳实践,为APP的未来发展绘制一幅清晰的蓝图。

完整效果展示

完整代码

dart 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(const ShoppingApp());
}

class ShoppingApp extends StatelessWidget {
  const ShoppingApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '淘淘购物',
      theme: ThemeData(
        primaryColor: Colors.orange,
        scaffoldBackgroundColor: Colors.grey[100],
        useMaterial3: true,
      ),
      home: const MainScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int _currentIndex = 0;
  final List<Widget> _screens = [
    const HomeScreen(),
    const CategoryScreen(),
    const CartScreen(),
    const ProfileScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _screens[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        type: BottomNavigationBarType.fixed,
        selectedItemColor: Colors.orange,
        unselectedItemColor: Colors.grey,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: '分类',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.shopping_cart),
            label: '购物车',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
    );
  }
}

// 首页
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('淘淘购物'),
        backgroundColor: Colors.orange,
        elevation: 0,
        actions: [
          IconButton(
            icon: const Icon(Icons.search),
            onPressed: () {},
          ),
          IconButton(
            icon: const Icon(Icons.message),
            onPressed: () {},
          ),
        ],
      ),
      body: ListView(
        children: [
          // 搜索框
          Container(
            padding: const EdgeInsets.all(10),
            color: Colors.orange,
            child: Container(
              padding: const EdgeInsets.symmetric(horizontal: 15),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(20),
              ),
              child: const TextField(
                decoration: InputDecoration(
                  hintText: '搜索宝贝',
                  border: InputBorder.none,
                  prefixIcon: Icon(Icons.search, color: Colors.grey),
                ),
              ),
            ),
          ),

          // 轮播图区域
          Container(
            height: 150,
            margin: const EdgeInsets.all(10),
            decoration: BoxDecoration(
              color: Colors.orange[300],
              borderRadius: BorderRadius.circular(10),
            ),
            child: const Center(
              child: Text(
                '轮播图区域',
                style: TextStyle(color: Colors.white, fontSize: 20),
              ),
            ),
          ),

          // 快捷入口
          Container(
            padding: const EdgeInsets.all(15),
            color: Colors.white,
            child: GridView.count(
              crossAxisCount: 5,
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              children: const [
                QuickEntry(Icons.shopping_bag, '天猫'),
                QuickEntry(Icons.card_giftcard, '聚划算'),
                QuickEntry(Icons.local_offer, '优惠券'),
                QuickEntry(Icons.phone_android, '数码'),
                QuickEntry(Icons.style, '服饰'),
                QuickEntry(Icons.home, '家居'),
                QuickEntry(Icons.restaurant, '美食'),
                QuickEntry(Icons.flight, '旅行'),
                QuickEntry(Icons.sports_basketball, '运动'),
                QuickEntry(Icons.book, '图书'),
              ],
            ),
          ),

          const SizedBox(height: 10),

          // 推荐商品
          Container(
            color: Colors.white,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Padding(
                  padding: EdgeInsets.all(15),
                  child: Text(
                    '为你推荐',
                    style: TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                GridView.builder(
                  shrinkWrap: true,
                  physics: const NeverScrollableScrollPhysics(),
                  padding: const EdgeInsets.all(10),
                  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    childAspectRatio: 0.75,
                    crossAxisSpacing: 10,
                    mainAxisSpacing: 10,
                  ),
                  itemCount: _recommendedProducts.length,
                  itemBuilder: (context, index) {
                    return ProductCard(product: _recommendedProducts[index]);
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// 快捷入口组件
class QuickEntry extends StatelessWidget {
  final IconData icon;
  final String label;

  const QuickEntry(this.icon, this.label, {super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Icon(icon, color: Colors.orange, size: 30),
        const SizedBox(height: 5),
        Text(label, style: const TextStyle(fontSize: 12)),
      ],
    );
  }
}

// 分类页
class CategoryScreen extends StatelessWidget {
  const CategoryScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('商品分类'),
        backgroundColor: Colors.orange,
      ),
      body: Row(
        children: [
          // 左侧分类列表
          Container(
            width: 100,
            color: Colors.grey[200],
            child: ListView.builder(
              itemCount: _categories.length,
              itemBuilder: (context, index) {
                return Container(
                  padding: const EdgeInsets.symmetric(vertical: 20),
                  decoration: BoxDecoration(
                    color: index == 0 ? Colors.white : null,
                    border: index == 0
                        ? const Border(
                            left: BorderSide(color: Colors.orange, width: 3))
                        : null,
                  ),
                  child: Center(
                    child: Text(
                      _categories[index],
                      style: TextStyle(
                        color: index == 0 ? Colors.orange : Colors.black87,
                        fontWeight:
                            index == 0 ? FontWeight.bold : FontWeight.normal,
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
          // 右侧商品列表
          Expanded(
            child: GridView.builder(
              padding: const EdgeInsets.all(10),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 3,
                childAspectRatio: 0.8,
                crossAxisSpacing: 10,
                mainAxisSpacing: 10,
              ),
              itemCount: _subCategories.length,
              itemBuilder: (context, index) {
                return SubCategoryCard(category: _subCategories[index]);
              },
            ),
          ),
        ],
      ),
    );
  }
}

// 子分类卡片
class SubCategoryCard extends StatelessWidget {
  final String category;

  const SubCategoryCard({super.key, required this.category});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          width: 60,
          height: 60,
          decoration: BoxDecoration(
            color: Colors.orange[100],
            borderRadius: BorderRadius.circular(10),
          ),
          child: const Icon(Icons.image, color: Colors.orange, size: 30),
        ),
        const SizedBox(height: 8),
        Text(
          category,
          style: const TextStyle(fontSize: 12),
          textAlign: TextAlign.center,
        ),
      ],
    );
  }
}

// 购物车页
class CartScreen extends StatefulWidget {
  const CartScreen({super.key});

  @override
  State<CartScreen> createState() => _CartScreenState();
}

class _CartScreenState extends State<CartScreen> {
  double _totalPrice = 0.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('购物车'),
        backgroundColor: Colors.orange,
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: _cartItems.length,
              itemBuilder: (context, index) {
                return CartItemCard(
                  item: _cartItems[index],
                  onQuantityChanged: (quantity) {
                    setState(() {
                      _totalPrice = _calculateTotal();
                    });
                  },
                );
              },
            ),
          ),
          // 底部结算栏
          Container(
            padding: const EdgeInsets.all(15),
            decoration: BoxDecoration(
              color: Colors.white,
              boxShadow: [
                BoxShadow(
                  color: Colors.grey.withOpacity(0.3),
                  blurRadius: 5,
                  offset: const Offset(0, -2),
                ),
              ],
            ),
            child: Row(
              children: [
                const Text(
                  '合计: ',
                  style: TextStyle(fontSize: 16),
                ),
                Text(
                  '¥$_totalPrice',
                  style: const TextStyle(
                    fontSize: 24,
                    color: Colors.orange,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const Spacer(),
                ElevatedButton(
                  onPressed: () {},
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.orange,
                    padding: const EdgeInsets.symmetric(
                      horizontal: 40,
                      vertical: 12,
                    ),
                  ),
                  child: const Text('结算', style: TextStyle(fontSize: 16)),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  double _calculateTotal() {
    return _cartItems.fold(
        0.0, (sum, item) => sum + item.price * item.quantity);
  }
}

// 我的页面
class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('我的淘淘'),
        backgroundColor: Colors.orange,
      ),
      body: ListView(
        children: [
          // 用户信息
          Container(
            padding: const EdgeInsets.all(20),
            color: Colors.orange,
            child: Column(
              children: [
                Container(
                  width: 80,
                  height: 80,
                  decoration: const BoxDecoration(
                    color: Colors.white,
                    shape: BoxShape.circle,
                  ),
                  child:
                      const Icon(Icons.person, size: 50, color: Colors.orange),
                ),
                const SizedBox(height: 10),
                const Text(
                  '用户昵称',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 5),
                Container(
                  padding:
                      const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.white),
                    borderRadius: BorderRadius.circular(15),
                  ),
                  child: const Text(
                    '登录/注册',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ],
            ),
          ),

          const SizedBox(height: 10),

          // 订单状态
          Container(
            padding: const EdgeInsets.all(15),
            color: Colors.white,
            child: Column(
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    const Text(
                      '我的订单',
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    Row(
                      children: const [
                        Text('全部订单', style: TextStyle(color: Colors.grey)),
                        Icon(Icons.chevron_right, color: Colors.grey),
                      ],
                    ),
                  ],
                ),
                const SizedBox(height: 15),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: const [
                    OrderStatusIcon(Icons.payment, '待付款'),
                    OrderStatusIcon(Icons.inventory, '待发货'),
                    OrderStatusIcon(Icons.local_shipping, '待收货'),
                    OrderStatusIcon(Icons.star, '待评价'),
                    OrderStatusIcon(Icons.replay, '退款/售后'),
                  ],
                ),
              ],
            ),
          ),

          const SizedBox(height: 10),

          // 功能列表
          Container(
            color: Colors.white,
            child: Column(
              children: const [
                ListTile(
                  leading: Icon(Icons.favorite_border, color: Colors.orange),
                  title: Text('我的收藏'),
                  trailing: Icon(Icons.chevron_right),
                ),
                Divider(height: 1),
                ListTile(
                  leading: Icon(Icons.location_on, color: Colors.orange),
                  title: Text('收货地址'),
                  trailing: Icon(Icons.chevron_right),
                ),
                Divider(height: 1),
                ListTile(
                  leading: Icon(Icons.help_outline, color: Colors.orange),
                  title: Text('联系客服'),
                  trailing: Icon(Icons.chevron_right),
                ),
                Divider(height: 1),
                ListTile(
                  leading: Icon(Icons.settings, color: Colors.orange),
                  title: Text('设置'),
                  trailing: Icon(Icons.chevron_right),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// 订单状态图标
class OrderStatusIcon extends StatelessWidget {
  final IconData icon;
  final String label;

  const OrderStatusIcon(this.icon, this.label, {super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Icon(icon, color: Colors.orange, size: 28),
        const SizedBox(height: 5),
        Text(label, style: const TextStyle(fontSize: 12)),
      ],
    );
  }
}

// 商品卡片
class ProductCard extends StatelessWidget {
  final Product product;

  const ProductCard({super.key, required this.product});

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(10),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.2),
            blurRadius: 5,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Expanded(
            child: Container(
              decoration: BoxDecoration(
                color: Colors.orange[100],
                borderRadius:
                    const BorderRadius.vertical(top: Radius.circular(10)),
              ),
              child: const Center(
                child: Icon(Icons.image, color: Colors.orange, size: 50),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  product.name,
                  style: const TextStyle(fontSize: 14),
                  maxLines: 2,
                  overflow: TextOverflow.ellipsis,
                ),
                const SizedBox(height: 5),
                Row(
                  children: [
                    Text(
                      '¥${product.price.toStringAsFixed(2)}',
                      style: const TextStyle(
                        color: Colors.orange,
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(width: 5),
                    Text(
                      '${product.sales}人付款',
                      style: const TextStyle(fontSize: 12, color: Colors.grey),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// 购物车商品卡片
class CartItemCard extends StatefulWidget {
  final CartItem item;
  final Function(int) onQuantityChanged;

  const CartItemCard({
    super.key,
    required this.item,
    required this.onQuantityChanged,
  });

  @override
  State<CartItemCard> createState() => _CartItemCardState();
}

class _CartItemCardState extends State<CartItemCard> {
  bool _isChecked = true;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(10),
      padding: const EdgeInsets.all(10),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(10),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.2),
            blurRadius: 5,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Row(
        children: [
          Checkbox(
            value: _isChecked,
            onChanged: (value) {
              setState(() {
                _isChecked = value ?? false;
              });
            },
          ),
          Container(
            width: 80,
            height: 80,
            decoration: BoxDecoration(
              color: Colors.orange[100],
              borderRadius: BorderRadius.circular(5),
            ),
            child: const Icon(Icons.image, color: Colors.orange),
          ),
          const SizedBox(width: 10),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  widget.item.name,
                  style: const TextStyle(fontSize: 14),
                  maxLines: 2,
                  overflow: TextOverflow.ellipsis,
                ),
                const SizedBox(height: 10),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      '¥${widget.item.price.toStringAsFixed(2)}',
                      style: const TextStyle(
                        color: Colors.orange,
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    Row(
                      children: [
                        IconButton(
                          icon: const Icon(Icons.remove, size: 18),
                          onPressed: () {
                            if (widget.item.quantity > 1) {
                              widget.item.quantity--;
                              widget.onQuantityChanged(widget.item.quantity);
                            }
                          },
                        ),
                        Text('${widget.item.quantity}'),
                        IconButton(
                          icon: const Icon(Icons.add, size: 18),
                          onPressed: () {
                            widget.item.quantity++;
                            widget.onQuantityChanged(widget.item.quantity);
                          },
                        ),
                      ],
                    ),
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// 数据模型
class Product {
  final String name;
  final double price;
  final int sales;

  Product({required this.name, required this.price, required this.sales});
}

class CartItem {
  final String name;
  final double price;
  int quantity;

  CartItem({
    required this.name,
    required this.price,
    this.quantity = 1,
  });
}

// 数据
final List<Product> _recommendedProducts = [
  Product(name: '新款智能手机', price: 2999.00, sales: 1000),
  Product(name: '无线蓝牙耳机', price: 199.00, sales: 5000),
  Product(name: '智能手表', price: 899.00, sales: 2000),
  Product(name: '运动鞋', price: 399.00, sales: 3000),
  Product(name: '男士休闲裤', price: 159.00, sales: 1500),
  Product(name: '女士连衣裙', price: 299.00, sales: 2500),
];

final List<String> _categories = [
  '热门推荐',
  '手机数码',
  '家用电器',
  '电脑办公',
  '家居家装',
  '服装服饰',
  '鞋靴箱包',
  '运动户外',
  '美妆个护',
  '食品生鲜',
];

final List<String> _subCategories = [
  '手机',
  '平板',
  '耳机',
  '充电宝',
  '数据线',
  '保护壳',
  '笔记本',
  '键盘',
  '鼠标',
  '显示器',
  '音响',
  '耳机',
  '冰箱',
  '洗衣机',
  '空调',
  '电视',
  '微波炉',
  '电饭煲',
];

final List<CartItem> _cartItems = [
  CartItem(name: '新款智能手机', price: 2999.00, quantity: 1),
  CartItem(name: '无线蓝牙耳机', price: 199.00, quantity: 2),
  CartItem(name: '智能手表', price: 899.00, quantity: 1),
];

第一步:痛点分析------当前架构的局限性

让我们先明确当前代码存在的主要问题:

  1. 数据与UI混杂 :所有的模拟数据(_recommendedProducts, _cartItems等)都定义在UI文件(如main.dart)的顶层。这导致UI文件臃肿不堪,且无法方便地替换为真实API数据。
  2. 状态管理脆弱 :购物车的总价计算依赖于CartScreen内部的_cartItems列表。这意味着,如果其他页面(如商品详情页)需要向购物车添加商品,就必须找到一种方式去修改CartScreen内部的状态,这破坏了组件的封装性。
  3. 缺乏可测试性 :业务逻辑(如总价计算)嵌入在StatefulWidget中,难以进行单元测试。
  4. 扩展性差:新增一个功能(如商品收藏)可能需要在多个地方修改代码,容易引入bug。

第二步:引入分层架构------Clean Architecture的简化版

为了解决上述问题,我们将采用一种简化的分层架构,将代码划分为三个核心层次:

  1. presentation (表现层) :即UI层。包含ScreensWidgetsProviders(状态管理)。它只负责展示数据和响应用户事件,不包含任何业务逻辑。
  2. domain (领域层) :包含核心的业务逻辑和数据模型。例如,ProductCartItem模型,以及CartService(负责计算总价、管理购物车项等)。
  3. data (数据层) :负责数据的获取和存储。包括repositories(仓库)和datasources(数据源,如API、本地数据库Hive/SQLite)。

第三步:拥抱现代化状态管理------Riverpod

要实现分层架构,我们需要一个强大的状态管理工具来连接各层。Riverpod 是目前Flutter社区公认的最佳选择之一,它相比setState和Provider有诸多优势:

  • 解耦:Provider的定义完全独立于UI树。
  • 安全:编译时检查,避免运行时错误。
  • 强大:支持异步、家族(Family)、监听等多种高级用法。
  • 可测试:Provider可以轻松地在测试中被覆盖。
重构购物车状态
  1. 定义CartService:

    dart 复制代码
    // domain/services/cart_service.dart
    class CartService {
      final List<CartItem> _items = [];
      List<CartItem> get items => _items;
      double get total => _items.fold(0, (sum, item) => sum + item.price * item.quantity);
    
      void addItem(CartItem item) { _items.add(item); }
      void removeItem(String productName) { _items.removeWhere((i) => i.name == productName); }
      void updateQuantity(String productName, int newQuantity) { /* ... */ }
    }
  2. 创建cartProvider:

    dart 复制代码
    // presentation/providers/cart_provider.dart
    final cartServiceProvider = Provider((ref) => CartService());
    final cartItemsProvider = Provider<List<CartItem>>((ref) {
      final service = ref.watch(cartServiceProvider);
      return service.items;
    });
    final cartTotalProvider = Provider<double>((ref) {
      final service = ref.watch(cartServiceProvider);
      return service.total;
    });
  3. 在UI中使用:

    dart 复制代码
    // 在CartScreen中
    final cartItems = ref.watch(cartItemsProvider);
    final totalPrice = ref.watch(cartTotalProvider);
    
    // 在商品详情页添加到购物车
    ref.read(cartServiceProvider).addItem(newItem);

现在,购物车的状态被集中管理在CartService中。任何页面都可以通过Provider安全地读取或修改购物车,彻底解决了状态共享的难题。

第四步:集成真实数据源

有了清晰的架构,集成真实数据变得水到渠成。

  1. 网络请求 :在data/datasources中创建ProductRemoteDataSource,使用httpdio库从RESTful
    API获取商品列表。
  2. 本地缓存 :使用Hiveshared_preferencesdata/datasources中创建CartLocalDataSource,在应用关闭后也能保存购物车数据。
  3. 仓库模式data/repositories/ProductRepository将协调远程和本地数据源,对外提供统一的Future<List<Product>> getAllProducts()接口。

表现层只需要调用ProductRepository,完全不用关心数据是从网络还是本地获取的。

第五步:未来功能展望

基于这套健壮的架构,我们可以轻松地扩展以下功能:

  • 用户认证 :引入AuthServiceauthProvider,管理用户登录状态。
  • 商品搜索与筛选 :在ProductRepository中增加带参数的查询方法。
  • 订单系统 :创建新的Order实体和OrderService,处理下单、支付等复杂流程。
  • 推送通知:集成Firebase Cloud Messaging (FCM),向用户发送促销信息或订单状态更新。
  • 性能优化 :使用ListView.builderitemExtent、图片懒加载(cached_network_image)等技术提升列表滚动性能。

结语

从一个简单的UI Demo,到一个具备清晰架构、可维护、可扩展的专业应用,我们走过了完整的演进之路。Flutter本身提供了强大的工具集,但如何组织和运用这些工具,才是区分业余与专业的关键。

通过引入分层架构和Riverpod,我们不仅解决了当前的问题,更重要的是为未来的所有可能性敞开了大门。代码不再是束缚,而是助力我们快速迭代、应对变化的坚实基石。

🌐 加入社区

欢迎加入 开源鸿蒙跨平台开发者社区 ,获取最新资源与技术支持:

👉 开源鸿蒙跨平台开发者社区


技术因分享而进步,生态因共建而繁荣

------ 晚霞的不甘 · 与您共赴鸿蒙跨平台开发之旅

相关推荐
Loo国昌2 小时前
【LangChain1.0】第十四阶段:Agent最佳设计模式与生产实践
人工智能·后端·算法·语言模型·架构
万岳科技系统开发2 小时前
配送外卖系统源码整体架构解析:从下单到配送的技术实现
架构
大雷神2 小时前
HarmonyOS智慧农业管理应用开发教程--高高种地--第15篇:地图导航与路线规划
华为·harmonyos
ujainu2 小时前
Flutter + OpenHarmony 底部导航栏:BottomNavigationBar 与 BottomAppBar 在多入口场景中的深度实践
flutter·组件
Easonmax2 小时前
基础入门 React Native 鸿蒙跨平台开发:栈操作可视化
react native·react.js·harmonyos
Easonmax2 小时前
基础入门 React Native 鸿蒙跨平台开发:链表操作可视化
react native·链表·harmonyos
AirDroid_cn2 小时前
鸿蒙NEXT:如何拦截第三方应用读取剪贴板内容?
华为·harmonyos
王同学 学出来2 小时前
React实操案例(四)
开发语言·react.js·前端框架