Flutter瀑布流布局深度实践:打造高性能动态图片墙

本文将深入探讨如何在Flutter中实现高性能瀑布流布局,解决动态高度内容展示的核心难题,并带来卓越的用户体验。

引言:瀑布流布局的魅力

瀑布流布局(Pinterest-style layout)已成为现代应用展示图片和内容的黄金标准。它通过错落有致的排列方式,自适应内容高度的特点,以及无限滚动的交互体验,为用户创造了流畅自然的浏览感受。

在Flutter中实现高性能瀑布流需要解决几个核心挑战:动态高度计算、高效图片加载、内存优化和流畅滚动体验。本文将循序渐进地解决所有这些问题。

一、瀑布流实现的核心架构

1.1 组件结构设计

我们采用模块化设计思想,将瀑布流拆分为三大核心组件:

WaterfallFlow(
items: items,// 数据源
columns: 2,// 列数
spacing: 16.0,// 列间距
itemBuilder: waterfallCard,// 自定义卡片构建器
onLoadMore: _loadMoreItems,// 滚动加载回调
)

1.2 瀑布流核心算法

关键算法在于将项目动态分配到各列中:

// 计算列宽
final columnWidth = (screenWidth - widget.spacing * (widget.columns - 1)) / widget.columns;// 创建列数组
final columns = List.generate(widget.columns, (index) => <dynamic>[]);// 循环分配项目到各列
for (int i = 0; i < widget.items.length; i++) {
columns[i % widget.columns].add(widget.items[i]);
}

这种简单的循环分配算法保证了内容在各列之间均匀分布,同时保持高效的性能。

二、动态高度图片处理的艺术

瀑布流的核心挑战在于处理任意高度的图片内容。我们使用IntrinsicHeight巧妙地解决这个问题:

2.1 AutoHeightImage组件

class _AutoHeightImage extends StatelessWidget {
final String imageUrl;
final double width;const _AutoHeightImage({required this.imageUrl, required this.width});
Widget build(BuildContext context) {
return CachedNetworkImage(
imageUrl: imageUrl,
width: width,
fit: BoxFit.cover,
placeholder: (context, url) => Container(
width: width,
height: width * 0.6,
color: Colors.grey[200],
),
errorWidget: (context, url, error) => Container(
width: width,
height: width * 0.6,
color: Colors.grey[200],
child: const Center(child: Icon(Icons.broken_image)),
),
imageBuilder: (context, imageProvider) {
return IntrinsicHeight(
child: Image(
image: imageProvider,
width: width,
fit: BoxFit.cover,
),
);
},
);
}
}

2.2 关键技术点解析

  1. IntrinsicHeight魔法:通过包裹Image组件,自动获取图片固有高度
  2. BoxFit.cover策略:保持图片原始比例不变形
  3. 双重占位机制
  • 加载前:灰色背景+默认宽高比
  • 加载失败:优雅的错误展示
  1. 高效缓存:使用cached_network_image优化网络加载

三、无限滚动与性能优化

3.1 滚动加载实现

void _scrollListener() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent - 200 &&
!_isLoading &&
widget.onLoadMore != null) {
_loadMoreItems();
}
}Future<void> _loadMoreItems() async {
if (_isLoading) return;setState(() => _isLoading = true);
try {
await widget.onLoadMore?.call();
} finally {
if (mounted) {
setState(() => _isLoading = false);
}
}
}

3.2 性能优化策略

  1. 缓存策略:使用CachedNetworkImage避免重复网络请求
  2. 懒加载:距离底部200px时触发加载,保持流畅体验
  3. 状态管理:精准控制加载状态,避免重复请求
  4. 列表重建优化:使用不可变数据集合,避免不必要的重绘
  5. 滚动监听销毁:在dispose中释放控制器资源

四、优雅的用户体验细节

4.1 美化卡片设计

Widget waterfallCard(BuildContext context, dynamic item, double width) {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
margin: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
// 图片部分
ClipRRect(
borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),
child: _AutoHeightImage(imageUrl: item['imageUrl'], width: width),
),// 文字内容
Padding(
padding: const EdgeInsets.all(12),
child: Column(/* 标题和描述 */),
),
],
),
);
}

4.2 回到顶部功能

Positioned(
bottom: 20,
right: 20,
child: FloatingActionButton(
onPressed: () => _scrollController.animateTo(0,
duration: const Duration(milliseconds: 500),
curve: Curves.easeOut),
child: const Icon(Icons.arrow_upward),
),
)

5.1 模拟数据生成

String getRandomImageUrl() {
final random = Random();
int randomNumber = random.nextInt(10);if (randomNumber < 2) {
return imageUrls[random.nextInt(imageUrls.length)];
} else {
int id = random.nextInt(1000) + 2;
return 'https://picsum.photos/300/200?random=$id';
}
}

这种混合数据源策略确保了:

  • 80%的图片来自picsum.photos的随机图
  • 20%的图片使用固定URL测试缓存性能
  • 部分卡片测试无标题/无描述的特殊情况

5.2 实际效果展示

在这里插入图片描述

瀑布流布局在真实设备上的运行效果:滚动流畅、图片加载自然、布局错落有致

六、完整代码结构

lib/
├── widgets/
│├── waterfall_flow_image_text.dart# 瀑布流核心组件
└── examples/
└── test_waterfall_flow_page.dart # 瀑布流示例页面

test_waterfall_flow_page.dart

import 'package:flutter/material.dart';
import '../../widgets/waterfall_flow_image_text.dart';
import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart';class WaterfallFlowExample extends StatefulWidget {const WaterfallFlowExample({Key? key}) : super(key: key);@overrideState<WaterfallFlowExample> createState() => _WaterfallFlowExampleState();
}class _WaterfallFlowExampleState extends State<WaterfallFlowExample> {List<Map<String, dynamic>> items = [];bool isLoading = false;int page = 1;@overridevoid initState() {super.initState();_loadInitialData();}void _loadInitialData() {setState(() {items = List.generate(30, (index) => _createItem(index));});}List<String> imageUrls = ['https://img0.baidu.com/it/u=933220220,287299241&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500','https://images.unsplash.com/photo-1461749280684-dccba630e2f6?auto=format&fit=crop&w=400&q=80',];String getRandomImageUrl() {final random = Random();int randomNumber = random.nextInt(10); // 0-9if (randomNumber < 2) {// Use imageUrls when random number is 0 or 1 (20% chance)return imageUrls[random.nextInt(imageUrls.length)];} else {// Use picsum.photos with random ID for numbers 2-9 (80% chance)int id = random.nextInt(1000) + 2; // Generates ID from 2 to 1001return 'https://picsum.photos/300/200?random=$id';}}Map<String, dynamic> _createItem(int id) {return {'id': id,'title': id == 0 ? '': '项目项目项目项目项目项目 $id','desc': id == 1 ? '':  '描述内容描述内容描述内容描述内容描述内容描述内容描述内容 $id',// 'imageUrl': 'https://picsum.photos/300/200?random=$id','imageUrl':getRandomImageUrl(),};}Future<void> _loadMoreItems() async {if (isLoading) return;setState(() => isLoading = true);await Future.delayed(const Duration(seconds: 1)); // 模拟网络请求setState(() {final newItems = List.generate(5, (i) => _createItem(items.length + i));items = [...items, ...newItems]; // 创建新列表(保持不可变性)isLoading = false;});}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('瀑布流演示')),body: WaterfallFlow(items: items,columns: 2,spacing: 16.0,itemBuilder: waterfallCard,onLoadMore: _loadMoreItems, // 传入加载更多回调),// body: Center(//   child: Column(//     mainAxisAlignment: MainAxisAlignment.center,//     children: [//       const Text('Image.network1:', style: TextStyle(fontWeight: FontWeight.bold)),//       Image.network('https://picsum.photos/250?image=9'),//       const Text('Image.network2:', style: TextStyle(fontWeight: FontWeight.bold)),//       Image.network(//         'https://docs.flutter.dev/assets/images/dash/dash-fainting.gif',//       ),//       // 调试块1:基本图片//       const Text('基本网络图片:', style: TextStyle(fontWeight: FontWeight.bold)),//       Container(//         color: Colors.yellow, // 调试背景//         padding: const EdgeInsets.all(8),//         child: SizedBox(//           width: 300,//           height: 200,//           child: Image.network(//             'https://img0.baidu.com/it/u=933220220,287299241&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',//             loadingBuilder: (context, child, progress) {//               if (progress == null) return child;//               return const Center(child: CircularProgressIndicator());//             },//             errorBuilder: (context, error, stack) {//               print('Image.network错误: $error');//               return const Icon(Icons.error, size: 50);//             },//           ),//         ),//       ),////       const SizedBox(height: 20),////       // 调试块2:CachedNetworkImage//       const Text('CachedNetworkImage:', style: TextStyle(fontWeight: FontWeight.bold)),//       // 使用 Expanded 包裹整个容器//       Expanded(//         child: Container(//           color: Colors.blue[100],//           padding: const EdgeInsets.all(8),//           child: CachedNetworkImage(//             imageUrl: 'https://images.unsplash.com/photo-1506744038136-46273834b3fb?auto=format&fit=crop&w=400&q=80',//             placeholder: (context, url) => const Center(child: CircularProgressIndicator()),//             errorWidget: (context, url, error) {//               print('CachedNetworkImage错误: $error');//               return const Icon(Icons.error, size: 50);//             },//             fit: BoxFit.cover, // 确保图片填充可用空间//           ),//         ),//       ),//     ],//   ),// ),);}
}

waterfall_flow_image_text.dart

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';class WaterfallFlow extends StatefulWidget {final List<Map<String, dynamic>> items;final int columns;final double spacing;final Widget Function(BuildContext, dynamic, double) itemBuilder;final Future<void> Function()? onLoadMore;const WaterfallFlow({super.key,required this.items,this.columns = 2,this.spacing = 12.0,required this.itemBuilder,this.onLoadMore,});@overrideState<WaterfallFlow> createState() => _WaterfallFlowState();
}class _WaterfallFlowState extends State<WaterfallFlow> {final ScrollController _scrollController = ScrollController();bool _isLoading = false;@overridevoid initState() {super.initState();_scrollController.addListener(_scrollListener);}void _scrollListener() {if (_scrollController.position.pixels >=_scrollController.position.maxScrollExtent - 200 &&!_isLoading &&widget.onLoadMore != null) {_loadMoreItems();}}Future<void> _loadMoreItems() async {if (_isLoading) return;setState(() => _isLoading = true);try {await widget.onLoadMore?.call();} finally {if (mounted) {setState(() => _isLoading = false);}}}@overrideWidget build(BuildContext context) {final screenWidth = MediaQuery.of(context).size.width;final columnWidth =(screenWidth - widget.spacing * (widget.columns - 1)) / widget.columns;// 简单按顺序分配项目到各列final columns = List.generate(widget.columns, (index) => <dynamic>[]);for (int i = 0; i < widget.items.length; i++) {columns[i % widget.columns].add(widget.items[i]);}return Stack(children: [ListView(controller: _scrollController,children: [Row(crossAxisAlignment: CrossAxisAlignment.start,children: List.generate(widget.columns, (columnIndex) {return Container(width: columnWidth,margin: EdgeInsets.only(right: columnIndex < widget.columns - 1 ? widget.spacing : 0),child: Column(crossAxisAlignment: CrossAxisAlignment.stretch,children: [for (var item in columns[columnIndex])widget.itemBuilder(context, item, columnWidth),],),);}),),if (_isLoading)const Padding(padding: EdgeInsets.all(16.0),child: Center(child: CircularProgressIndicator()),),],),Positioned(bottom: 20,right: 20,child: FloatingActionButton(onPressed: () => _scrollController.animateTo(0,duration: const Duration(milliseconds: 500),curve: Curves.easeOut),backgroundColor: Colors.blue,child: const Icon(Icons.arrow_upward, color: Colors.white),),),],);}@overridevoid dispose() {_scrollController.dispose();super.dispose();}
}// 瀑布流卡片 - 完全动态高度
Widget waterfallCard(BuildContext context, dynamic item, double width) {return Card(elevation: 3,shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12),),margin: const EdgeInsets.only(bottom: 12),child: Column(crossAxisAlignment: CrossAxisAlignment.start,mainAxisSize: MainAxisSize.min,children: [// 图片部分 - 使用IntrinsicHeight保持比例ClipRRect(borderRadius: const BorderRadius.vertical(top: Radius.circular(12)),child: _AutoHeightImage(imageUrl: item['imageUrl'],width: width,),),// 文字内容部分Padding(padding: const EdgeInsets.all(12),child: Column(crossAxisAlignment: CrossAxisAlignment.start,mainAxisSize: MainAxisSize.min,children: [if (item['title']?.isNotEmpty == true)Padding(padding: const EdgeInsets.only(bottom: 6),child: Text(item['title'],style: const TextStyle(fontSize: 16,fontWeight: FontWeight.bold,),maxLines: 2,overflow: TextOverflow.ellipsis,),),if (item['desc']?.isNotEmpty == true)Text(item['desc'],style: TextStyle(color: Colors.grey[600],fontSize: 14,),maxLines: 2,overflow: TextOverflow.ellipsis,),],),),],),);
}// 自动高度图片组件
class _AutoHeightImage extends StatelessWidget {final String imageUrl;final double width;const _AutoHeightImage({required this.imageUrl,required this.width,});@overrideWidget build(BuildContext context) {return CachedNetworkImage(imageUrl: imageUrl,width: width,fit: BoxFit.cover,placeholder: (context, url) => Container(width: width,height: width * 0.6, // 默认比例color: Colors.grey[200],child: const Center(child: CircularProgressIndicator()),),errorWidget: (context, url, error) => Container(width: width,height: width * 0.6,color: Colors.grey[200],child: const Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Icon(Icons.broken_image, size: 40, color: Colors.grey),SizedBox(height: 8),Text('加载失败', style: TextStyle(color: Colors.grey)),],),),),imageBuilder: (context, imageProvider) {return IntrinsicHeight(child: Image(image: imageProvider,width: width,fit: BoxFit.cover,),);},);}
}

七、Flutter图片加载失败

🔧 步骤1:彻底重置设备网络栈(关键!)
# 终止所有ADB进程
adb kill-server# 清除DNS缓存和网络设置
adb shell settings delete global captive_portal_mode
adb shell settings delete global captive_portal_server
adb shell settings put global captive_portal_mode 0
adb shell settings put global captive_portal_detection_enabled 0
adb shell ndc resolver flushdefaultif
adb shell ndc resolver clearnetdns# 强制使用Google DNS
adb shell ndc resolver setdefaultif eth0
adb shell ndc resolver setifdns eth0 8.8.8.8 8.8.4.4# 重启网络接口
adb shell svc wifi disable
adb shell svc data disable
sleep 3# 等待网络完全关闭
adb shell svc wifi enable
adb shell svc data enable# 重启ADB服务
adb start-server

原理:Android系统DNS缓存污染是图片加载失败的常见元凶,此操作彻底清理网络状态,解决80%的偶发性问题。


🔐 步骤2:修改网络安全配置

android/app/src/main/res/xml/network_security_config.xml 中添加:

<network-security-config>
<!-- 允许HTTP明文传输 -->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system"/>
<certificates src="user"/>
</trust-anchors>
</base-config><!-- 专门放行图片CDN域名 -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">*.picsum.photos</domain>
<domain includeSubdomains="true">*.unsplash.com</domain>
<domain includeSubdomains="true">*.baidu.com</domain>
<trust-anchors>
<certificates src="system"/>
<certificates src="user"/>
</trust-anchors>
</domain-config>
</network-security-config>

注意:在 AndroidManifest.xml 中启用此配置:

<uses-permission android:name="android.permission.INTERNET" />
<application
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
... >

结语:瀑布流的艺术与科学

通过本文的实践,我们成功打造了一个高性能的Flutter瀑布流组件。关键点在于:

  1. 使用IntrinsicHeight解决动态高度问题
  2. 结合CachedNetworkImage实现高效图片加载
  3. 精准控制滚动加载逻辑
  4. 注重用户体验细节

这些技术的结合使得我们的瀑布流不仅在视觉上吸引人,而且在性能上表现出色。随着Flutter的不断发展,我们可以期待更多优化瀑布流的方案出现,但本文的核心思想和方法论将长期有效。

最好的UI是看不见的UI——当用户沉浸在你的内容中而没有注意到布局本身时,说明你的瀑布流实现达到了完美境界。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89223.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV 伽马校正函数gammaCorrection()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数用于对输入图像应用伽马校正&#xff08;Gamma Correction&#xff09;&#xff0c;这是一种非线性的图像处理技术&#xff0c;主要用于调整…

Linux-局域网构建+VLAN 划分 + 端口 MAC-IP 绑定 + 静态 DHCP

文章目录1. 适用于家庭、工作室或小型企业的局域网构建2. VLAN划分3. VLAN 划分 端口 MAC-IP 绑定 静态 DHCP跳转→网络管理基础复习 1. 适用于家庭、工作室或小型企业的局域网构建 ✅ 一、硬件连线&#xff08;一次到位&#xff09; 光纤入户 → 光猫/宽带调制解调器光猫…

渗透测试路线

渗透测试学习路线报告&#xff08;从入门到高级&#xff09; 引言&#xff1a;渗透测试概述与学习路线设计 渗透测试作为网络安全体系中的核心实践环节&#xff0c;通过模拟真实攻击者的技术手段与攻击路径&#xff0c;主动识别信息系统中的安全漏洞、评估防护机制有效性&#…

Node.js 中http 和 http/2 是两个不同模块对比

1. 核心模块对比 特性http 模块 (HTTP/1.1)http2 模块 (HTTP/2)协议版本HTTP/1.1&#xff08;文本协议&#xff09;HTTP/2&#xff08;二进制协议&#xff09;多路复用不支持&#xff08;需多个 TCP 连接&#xff09;支持&#xff08;单连接多流&#xff09;头部压缩无HPACK 压…

3DGS之COLMAP

COLMAP 在 3DGS 中起到了数据预处理和三维重建的关键作用&#xff0c;其处理流程包括特征提取与匹配、稀疏重建、稠密重建和输出文件生成。结合 3DGS 的高斯分布建模和优化算法&#xff0c;COLMAP 提供了场景的几何和相机信息&#xff0c;为实时渲染和三维重建奠定了基础。一、…

RabbitMQ中队列长度限制(Queue Length Limit)详解

在 RabbitMQ 中&#xff0c;队列长度限制&#xff08;Queue Length Limit&#xff09;是指对队列中消息数量的最大限制。当队列中的消息数量达到设定的上限时&#xff0c;RabbitMQ 会根据配置的策略&#xff08;如丢弃旧消息、拒绝新消息或将消息转移到另一个队列&#xff09;来…

Python设计模式深度解析:建造者模式(Builder Pattern)完全指南

Python设计模式深度解析&#xff1a;建造者模式&#xff08;Builder Pattern&#xff09;完全指南前言什么是建造者模式&#xff1f;建造者模式的核心思想模式的核心组成实际案例一&#xff1a;UI选择组件的动态构建抽象建造者基类具体建造者实现列表框建造者复选框建造者工厂建…

elementuiPlus+vue3手脚架后台管理系统,上生产环境之后,如何隐藏vite.config.ts的target地址

在项目根目录创建 .env.production 文件&#xff1a; VITE_API_TARGEThttps://your-real-api.com修改 vite.config.ts&#xff1a; import { defineConfig, loadEnv } from viteexport default defineConfig(({ mode }) > {const env loadEnv(mode, process.cwd(), )return…

ARCGIS PRO DSK 颜色选择控件(ColorPickerControl)的调用

颜色选择控件ColorPickerControl 。一、XAML 集成方式 1 、在WPF窗体上使用&#xff0c;xml&#xff1a;加入空间命名引用xmlns:ui1"clr-namespace:ArcGIS.Desktop.Internal.Mapping.Symbology;assemblyArcGIS.Desktop.Mapping" xmlns:uil"http://schemas.xceed…

深浅拷贝以及函数缓存

目录 数据类型介绍 基本数据类型&#xff08;Primitive Types&#xff09; 引用数据类型&#xff08;Reference Types&#xff09; 浅拷贝 深拷贝 利用JSON的序列化和反序列化实现深拷贝 递归实现深拷贝 第三方库lodash的cloneDeep 函数缓存的概念 实现方法 数据类型介…

第六届信号处理与计算机科学国际学术会议(SPCS 2025)

重要信息 官网&#xff1a;www.icspcs.org &#xff08;详情见官网&#xff09; 时间&#xff1a;2025年8月15-17日 地点&#xff1a;西安 主题 信号处理与智能计算计算科学与人工智能网络与多媒体技术数字信号处理 雷达信号处理 通信信号处理 临时和传感器网络 模拟和…

MongoDB:一个灵活的、可扩展的 NoSQL 数据库

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…

系统思考场景应用

最近一直在与不同行业头部企业共同探讨系统思考这个主题。一些新的合作伙伴也常常问我&#xff0c;系统思考究竟能为客户解决什么痛点&#xff1f; 这两天上课客户的核心需求是&#xff1a;全局思维。在过去的几年里&#xff0c;我深切体会到&#xff0c;随着外部环境的快速变化…

SQL预编译:安全高效数据库操作的关键

通过占位符&#xff08;如 ? 或命名参数&#xff09;编写预编译的 SQL 语句&#xff08;通常通过 PreparedStatement 实现&#xff09;是数据库操作的最佳实践&#xff0c;主要好处包括&#xff1a;&#x1f512; 1. 防止 SQL 注入攻击&#xff08;核心安全优势&#xff09; 问…

springboot实验室管理系统-计算机毕业设计源码20916

摘 要 随着高校实验室管理需求的不断增加&#xff0c;传统的管理方式已经难以满足现代教育的要求。为了解决这一问题&#xff0c;本文设计并实现了一种基于VUE和SpringBoot的实验室管理系统。该系统采用前后端分离的架构&#xff0c;前端使用VUE框架&#xff0c;后端基于Sprin…

spdringboot共享学习室小程序 计算机毕业设计源码27728

摘 要 共享学习室小程序是一款基于SpringBoot框架开发的移动端应用&#xff0c;旨在提供一个便捷的自习室预约、管理和资源共享平台。通过该小程序&#xff0c;用户可以方便地预约自习室、查看资讯、提交反馈意见&#xff0c;同时进行失物招领、查看订单信息等多项操作。对于管…

JVM——JVM 的内存区域是如何划分的?

Java 虚拟机运行时数据区分为方法区、堆、虚拟机栈、本地方法栈、程序计数器。 方法区(Method Area): [1] 存储类信息、常量、静态变量和即时编译器(JIT)编译后的代码。 [2] 属于线程共享区域&#xff0c;所有线程共享方法区内存 [3] 在 JDK8之前&#xff0c;HotSpot使用永久代…

SpringAi笔记

简介 :: Spring AI 中文文档 Spring AI 解决了 AI 集成的根本难题&#xff1a;将企业数据和 API 与 AI 模型连接起来。 聊天客户端 API (ChatClient ) 发起对模型的调用和响应 创建&#xff1a;其中可以通过bean来注入创建好的chatClient 可以使用Qualifier注解&#xff0c;…

基于SD-WAN的智慧高速解决方案:高效、低成本的智能交通实践

随着交通网络的智能化需求逐渐增加&#xff0c;智慧高速建设已成为提升通行效率、优化安全性、实现交通现代化管理的重要方向。在本文中&#xff0c;我们将以某智慧高速项目为例&#xff0c;详细探讨如何通过 SD-WAN 技术与多种智能化手段结合&#xff0c;实现“低成本、高效率…

Towards Low Light Enhancement with RAW Images 论文阅读

利用 RAW 图像实现低光增强 摘要 在本文中&#xff0c;我们首次进行了基准研究&#xff0c;详细阐述了在低光增强中使用 RAW 图像的优越性&#xff0c;并提出了一种新颖的替代方案&#xff0c;以更灵活和实用的方式利用 RAW 图像。受对典型图像处理流程的全面考虑启发&#xff…