Launcher3主页面加载显示流程分析
布局结构
抓取布局后,可以看到每个图标是一个DoubleShadowBubbleTextView,父布局是CellLayout、workspace。
我们可以在CellLayout添加子view打印出调用堆栈信息,可以整体上看页面加载显示流程。
主要类
- Launcher.java:主界面,即MainActivity
- launcher.xml:主界面布局文件
- LauncherModel.java:管理Launcher状态,包括加载任务、状态回调等
- LoaderTask.java:加载任务,是一个Runnable
- LoaderResults.java:加载结果
- BgDataModel#Callbacks:数据回调接口,Launcher实现该接口,加载任务通过该接口回调给Launcher
- LauncherProvider:桌面数据提供者,采用db保存桌面图标数据(包括排列位置、类型等)
- LauncherSettings:封装访问LauncherProvider时的uri、column等一些常量,通过ContentResolver来访问LauncherProvider,不直接操作db
- LoaderCursor:封装cursor操作
流程图

创建Activity
主界面创建的时候,常规的setContentView和findView,创建LauncherModel并开始加载数据
// Launcher.java
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 1.创建LauncherAppState和LauncherModelLauncherAppState app = LauncherAppState.getInstance(this);mModel = app.getModel();// 2.infalte布局文件,找到viewsetupViews();// 3. 设置loader监听,开始加载数据,加载完成后回调给主界面if (!mModel.addCallbacksAndLoad(this)) {if (!internalStateHandled) {// If we are not binding synchronously, pause drawing until initial bind complete,// so that the system could continue to show the device loading promptmOnInitialBindListener = Boolean.FALSE::booleanValue;}}// 4. 设置view给ActivitysetContentView(getRootView());
加载数据
创建加载任务
mModel.addCallbacksAndLoad将Launcher设置给LauncherModel,然后创建了加载任务
// LauncherModel.java
/*** Adds a callbacks to receive model updates* @return true if workspace load was performed synchronously*/
public boolean addCallbacksAndLoad(@NonNull final Callbacks callbacks) {synchronized (mLock) {addCallbacks(callbacks);return startLoader(new Callbacks[] { callbacks });}
}private boolean startLoader(@NonNull final Callbacks[] newCallbacks) {synchronized (mLock) {// 1.取消旧的加载任务boolean wasRunning = stopLoader(); // 之前没有loader任务,wasRunning为falseboolean bindDirectly = mModelLoaded && !mIsLoaderTaskRunning;// 之前没有加载过,bindDirectly为falseboolean bindAllCallbacks = wasRunning || !bindDirectly || newCallbacks.length == 0; // bindAllCallbacks为true, 上一步已经addCallbacks了,所以callbacksList里面包含从Launcher.java传进来的callbacksfinal Callbacks[] callbacksList = bindAllCallbacks ? getCallbacks() : newCallbacks;if (callbacksList.length > 0) {// 2.清空PendingBindfor (Callbacks cb : callbacksList) {MAIN_EXECUTOR.execute(cb::clearPendingBinds);}// 3.创建LoaderResults和LoaderTask,开始加载数据LoaderResults loaderResults = new LoaderResults(mApp, mBgDataModel, mBgAllAppsList, callbacksList);if (bindDirectly) {loaderResults.bindWorkspace(bindAllCallbacks);loaderResults.bindAllApps();loaderResults.bindDeepShortcuts();loaderResults.bindWidgets();return true;} else {stopLoader();mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);MODEL_EXECUTOR.post(mLoaderTask);}}}
}
整体加载步骤
LoaderTask#run中根据类型加载步骤分为了5步,图标的加载主要看第一步
// LoaderTask.java
public void run() {try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {// first stepList<ShortcutInfo> allShortcuts = new ArrayList<>();loadWorkspace(allShortcuts, memoryLogger);// Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.// sanitizeData should not be invoked if the workspace is loaded from a db different// from the main db as defined in the invariant device profile.// (e.g. both grid preview and minimal device mode uses a different db)if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {sanitizeData();}mResults.bindWorkspace(true /* incrementBindId */);mModelDelegate.workspaceLoadComplete();// Notify the installer packages of packages with active installs on the first screen.sendFirstScreenActiveInstallsBroadcast();// Take a breakwaitForIdle();// second stepList<LauncherActivityInfo> allActivityList;allActivityList = loadAllApps();mResults.bindAllApps();IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();setIgnorePackages(updateHandler);updateHandler.updateIcons(allActivityList,LauncherActivityCachingLogic.newInstance(mApp.getContext()),mApp.getModel()::onPackageIconsUpdated);updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),mApp.getModel()::onPackageIconsUpdated);waitForIdle();// third stepList<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();mResults.bindDeepShortcuts();updateHandler.updateIcons(allDeepShortcuts,new ShortcutCachingLogic(), (pkgs, user) -> { });waitForIdle();// fourth stepList<ComponentWithLabelAndIcon> allWidgetsList =mBgDataModel.widgetsModel.update(mApp, null);mResults.bindWidgets();updateHandler.updateIcons(allWidgetsList,new ComponentWithIconCachingLogic(mApp.getContext(), true),mApp.getModel()::onWidgetLabelsUpdated);// fifth steploadFolderNames();updateHandler.finish();mModelDelegate.modelLoadComplete();transaction.commit();} catch (CancellationException e) {...}
}
图标解析
loadWorkspace()代码比较多,主要作用是通过ContentResolver查询LauncherProvider中保存的桌面图标信息,然后遍历cursor来解析数据。
在分析代码的时候,抓到数据流向,可以结合真实的db数据进行分析,其中一些判断容错处理可以跳过
主要流程如下:
- 加载默认的数据(Provider会有判断,只有第一次才会加载)
- 通过ContentResolver查询所有数据
- 遍历cursor,根据不同图标类型进行解析,如ITEM_TYPE_APPLICATION代表普通的图标,ITEM_TYPE_FOLDER代表文件夹
- 对数据进行一些校验,校验通过后将数据添加到mBgDataModel
数据流向:
Db(LauncherProvider) --> Cursor(LoaderCursor) --> List(BgDataModel)
protected void loadWorkspace(List<ShortcutInfo> allDeepShortcuts,Uri contentUri,String selection,@Nullable LoaderMemoryLogger logger) {final Context context = mApp.getContext();final ContentResolver contentResolver = context.getContentResolver();// 1. 加载默认的数据(Provider会有判断,只有第一次才会加载)LauncherSettings.Settings.call(contentResolver,LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);synchronized (mBgDataModel) {mBgDataModel.clear();mPendingPackages.clear();// 2. 查询所有数据final LoaderCursor c = new LoaderCursor(contentResolver.query(contentUri, null, selection, null, null), contentUri,mApp, mUserManagerState);final Bundle extras = c.getExtras();mDbName = extras == null? null : extras.getString(LauncherSettings.Settings.EXTRA_DB_NAME);try {// 2.1 遍历cursorfinal int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);final int appWidgetProviderIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_PROVIDER);final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);final int rankIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RANK);final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);final int sourceContainerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_SOURCE);WorkspaceItemInfo info;LauncherAppWidgetInfo appWidgetInfo;LauncherAppWidgetProviderInfo widgetProviderInfo;Intent intent;String targetPkg;List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();while (!mStopped && c.moveToNext()) {try {// 2.2 根据不同图标类型进行解析,ITEM_TYPE_APPLICATION代表普通的图标,ITEM_TYPE_FOLDER代表文件夹switch (c.itemType) {case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:intent = c.parseIntent();// 2.3 解析数据,进行一些校验判断if (info != null) {if (info.itemType!= LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {// Skip deep shortcuts; their title and icons have already been// loaded above.iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));}c.applyCommonProperties(info);info.intent = intent;info.rank = c.getInt(rankIndex);info.spanX = 1;info.spanY = 1;info.runtimeStatusFlags |= disabledState;if (isSafeMode && !isSystemApp(context, intent)) {info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;}LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();if (activityInfo != null) {info.setProgressLevel(PackageManagerHelper.getLoadingProgress(activityInfo),PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);}if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {tempPackageKey.update(targetPkg, c.user);SessionInfo si = installingPkgs.get(tempPackageKey);if (si == null) {info.runtimeStatusFlags &=~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;} else if (activityInfo == null) {int installProgress = (int) (si.getProgress() * 100);info.setProgressLevel(installProgress,PackageInstallInfo.STATUS_INSTALLING);}}// 3.将数据添加到mBgDataModelc.checkAndAddItem(info, mBgDataModel, logger);} else {throw new RuntimeException("Unexpected null WorkspaceItemInfo");}break;case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);c.applyCommonProperties(folderInfo);// Do not trim the folder label, as is was set by the user.folderInfo.title = c.getString(c.titleIndex);folderInfo.spanX = 1;folderInfo.spanY = 1;folderInfo.options = c.getInt(optionsIndex);// no special handling required for restored foldersc.markRestored();c.checkAndAddItem(folderInfo, mBgDataModel, logger);break;}} catch (Exception e) {Log.e(TAG, "Desktop items loading interrupted", e);}}} finally {IOUtils.closeSilently(c);}// Load delegate itemsmModelDelegate.loadItems(mUserManagerState, shortcutKeyToPinnedShortcuts);// Load string cachemModelDelegate.loadStringCache(mBgDataModel.stringCache);// Remove dead itemsmItemsDeleted = c.commitDeleted();// Sort the folder items, update ranks, and make sure all preview items are high res.FolderGridOrganizer verifier =new FolderGridOrganizer(mApp.getInvariantDeviceProfile());for (FolderInfo folder : mBgDataModel.folders) {Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);verifier.setFolderInfo(folder);int size = folder.contents.size();// Update ranks here to ensure there are no gaps caused by removed folder items.// Ranks are the source of truth for folder items, so cellX and cellY can be ignored// for now. Database will be updated once user manually modifies folder.for (int rank = 0; rank < size; ++rank) {WorkspaceItemInfo info = folder.contents.get(rank);info.rank = rank;if (info.usingLowResIcon()&& info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION&& verifier.isItemInPreview(info.rank)) {mIconCache.getTitleAndIcon(info, false);}}}c.commitRestoredItems();}
}
可以结合db数据进行分析:
- container: 表示显示的布局,像普通、文件夹、dock栏等
- screen: 表示现在第几屏
- itemType:表示类型,像应用图标、文件夹、快捷方式等

图标显示
到这里,我们已经获取到桌面数据了,下面就是要设置到view显示出来。在上面LoaderTask#run()中,loadWorkspace()获取到了数据,而ui显示的触发在mResults.bindWorkspace(true)
bindWorkspace()先是将数据复制一份,然后遍历callback进行bind。上一步mBgDataModel保存了数据库中数据,mBgDataModel是LauncherModel的一个成员变量,在activity#onCreate时创建的,而activity就是Callbacks,所以到这里都关联了起来。
Launcher (Callbacks)—> LoaderTask —> LoaderResults --> BgDataModel --> Callbacks
// LoaderResults.java
/*** Binds all loaded data to actual views on the main thread.*/
public void bindWorkspace(boolean incrementBindId) {// Save a copy of all the bg-thread collectionsArrayList<ItemInfo> workspaceItems = new ArrayList<>();ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();final IntArray orderedScreenIds = new IntArray();ArrayList<FixedContainerItems> extraItems = new ArrayList<>();synchronized (mBgDataModel) {workspaceItems.addAll(mBgDataModel.workspaceItems);appWidgets.addAll(mBgDataModel.appWidgets);orderedScreenIds.addAll(mBgDataModel.collectWorkspaceScreens());mBgDataModel.extraItems.forEach(extraItems::add);if (incrementBindId) {mBgDataModel.lastBindId++;}mMyBindingId = mBgDataModel.lastBindId;}for (Callbacks cb : mCallbacksList) {new WorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId,workspaceItems, appWidgets, extraItems, orderedScreenIds).bind();}
}
WorkspaceBinder中bind方法会执行callback回调,回调到activity后,创建BubbleTextView添加到CellLayout。
相关文章:
Launcher3主页面加载显示流程分析
布局结构 抓取布局后,可以看到每个图标是一个DoubleShadowBubbleTextView,父布局是CellLayout、workspace。 我们可以在CellLayout添加子view打印出调用堆栈信息,可以整体上看页面加载显示流程。 主要类 Launcher.java:主界面&…...
【读书笔记·VLSI电路设计方法解密】问题36:一个好的设计流程有哪些特点
由于IC实现与不断演进的技术节点密切相关,且各种新问题迅速涌现,一个优秀的设计流程必须具备灵活性,以应对这些新挑战,而无需进行大规模调整。 与此同时,为了克服当今SoC实现领域中出现的众多问题,整个EDA行业正在高速运转。新工具正在加速涌现;因此,一个优秀的设计流…...
C语言----共用体、枚举
目录 编辑 共用体 1. 定义 2. 格式 注意: 枚举 1. 定义: 2. 格式: 3. 说明: 面试题:枚举和宏定义区别? 共用体 1. 定义 不同数据类型的数据可以使用共同的存储区域,这种数据构造类…...
26.Java Lock 接口(synchronized 关键字回顾、可重入锁快速入门、Lock 对比 synchronized)
一、synchronized 关键字 1、synchronized 关键字回顾 synchronized 是 Java 中的关键字,是一种同步锁,它修饰的对象有以下几种 修饰一个类:其作用的范围是 synchronized 后面括号括起来的部分,作用的对象是这个类的所有对象 修…...
机器学习 学习知识点
机器学习 学习知识点 什么是消融实验(Ablation experiment)?num_step与batch_size的区别python glob.glob()函数认识python的条件判断之is not、is not None、is Nonetqdm介绍及常用方法softmax 激活函数。type_as(tesnor)Python OpenCV cv2.…...
GESP真题 | 2024年12月1级-编程题4《美丽数字》及答案(C++版)
描述 小杨有 n 个正整数,他认为一个正整数是美丽数字当且仅当该正整数是 9 的倍数但不是 8 的倍数。 小杨想请你编写一个程序计算个正整数中美丽数字的数量。 输入描述 第一行包含一个正整数 n,代表正整数个数 。 第二行包含 n 个正整数 a1, a2, a3…...
java并发之AQS
一、简介 AQS,全称:AbstractQueuedSynchronizer,是一个JDK提供的用于构建锁、同步器等线程协作工具类的框架,内部维护FIFO双向队列(双向链表实现)。 AQS重要属性: // 表示同步状态。它既可以表…...
4 种修复 IPhone 备份输入密码解锁的方法
您是否在 iTunes 中遇到过这样的消息:“输入密码以解锁您的 iPhone 备份”?出现这种情况是因为备份具有加密备份。当您通过 iTunes 为 iPhone 创建此备份时,您需要生成 iTunes 备份密码来保护和加密您的 iPhone 备份。当您想要更改 iPhone 备…...
选课(贪心)
小明是个好学的程序猿,他想在一天内尽可能多的选择课程进行学习。在下列课程中,他能选择的最多课程是几门? 输入格式: 第一行为一个整数n,表示课程总数。接下来每行为x,y,z表示课程名,开始时间…...
【深度学习】Java DL4J基于 LSTM 构建新能源预测模型
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探…...
【linux基础I/O(1)】文件描述符的本质重定向的本质
目录 前言1. 理解C语言的文件接口2. 操作文件的系统调用接口2.1 open函数详解2.2 close函数详解2.3 write函数详解2.4 read函数详解 3. 文件描述符fd详解4. 文件描述符的内核本质5. 怎样理解Linux下一切皆文件?6. 理解输出输入重定向7. 重定向的系统调用8. 总结 前言 “在Lin…...
微服务架构下的慢请求排查与优化策略
目录 一、分析请求路径 二、检查日志 三、进行时序分析 四、检查资源消耗 五、检查并发处理能力 六、检查网络连接 七、从根本上使用服务治理的方式解决问题 八、结语 在当今的数字化时代,企业为了应对快速变化的市场需求和日益增长的用户基数,纷…...
C++ 中 Unicode 字符串的宽度
首先,什么是 Unicode? Unicode 实际上是一个统一的文字编码标准,它出现目的是为了解决不同计算机之间字符编码不同而导致的灾难性不兼容问题。 Unicode 字符集与 Unicode 编码是两种不同的概念。Unicode 字符集实际是对进入标准的所有文字用…...
人工智能在SEO中的应用与关键词优化策略
内容概要 随着科技的迅猛发展,人工智能在搜索引擎优化(SEO)中的应用逐渐成为业界关注的热点。AI技术不仅可以有效提高关键词的优化策略,还能在提升内容效率、增强用户体验方面发挥重要作用。通过对相关技术的深入探讨,…...
spring mvc源码学习笔记之四
pom.xml 内容如下 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…...
ruckus R510升级到Unleashe后不能访问
ruckus R510 是IPQ4019,升级到Unleashe,它弹窗提示 但是这个IP没办法用,访问不了AP。 必应了一下,官方提示用advance ip scanner扫描。 扫描持续好久,发现IP竟然是从主路由获得。 9090的端口不用填,甚至不…...
【游戏设计原理】47 - 超游戏思维
对于这条原理,我首先想到的是开放世界,或者探索性游戏,这是最能包容各类玩家的游戏类型。这类游戏定义了基本规则,玩家的可操作性很强。就像上图里的沙池一样,里面有滑梯,是规则性比较明确的,而…...
FastAPI vs Flask 专业对比与选择
FastAPI与Flask是两个流行的Python Web框架,它们在构建Web应用程序和API方面各有特点。以下是对这两个框架的详细比较: 一、设计理念与用途 Flask: 是一个轻量级的Python Web框架,基于Werkzeug WSGI工具箱和Jinja2模板引擎。设计…...
【信息系统项目管理师】【综合知识】【备考知识点】【思维导图】第十一章 项目成本管理
word版☞【信息系统项目管理师】【综合知识】【备考知识点】第十一章 项目成本管理 移动端【思维导图】☞【信息系统项目管理师】【思维导图】第十一章 项目成本管理...
xdoj-字符串-556,为什么字符不能被正常读入
目录 题目 代码 测试用例 the input the correct output 问题发现过程阐述 如果把line16中的数组大小11换成line17中的10 case 1 case 2 case 3 如果数组开成11 case4 代码分析 问题描述 Question1 Question2 题目 题目:连续数字字符串提取 问题描述…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...
数据可视化交互
目录 【实验目的】 【实验原理】 【实验环境】 【实验步骤】 一、安装 pyecharts 二、下载数据 三、实验任务 实验 1:AQI 横向对比条形图 代码说明: 运行结果: 实验 2:AQI 等级分布饼图 实验 3:多城市 AQI…...
Python 解释器安装全攻略(适用于 Linux / Windows / macOS)
目录 一、Windows安装Python解释器1.1 下载并安装Python解释1.2 测试安装是否成功1.3 设置pip的国内镜像------永久配置 二、macOS安装Python解释器三、Linux下安装Python解释器3.1 Rocky8.10/Rocky9.5安装Python解释器3.2 Ubuntu2204/Ubuntu2404安装Python解释器3.3 设置pip的…...
Razor编程中@Helper的用法大全
文章目录 第一章:Helper基础概念1.1 Helper的定义与作用1.2 Helper的基本语法结构1.3 Helper与HtmlHelper的区别 第二章:基础Helper用法2.1 无参数Helper2.2 带简单参数的Helper2.3 带默认值的参数2.4 使用模型作为参数 第三章:高级Helper用法…...
2025年ESWA SCI1区TOP,自适应学习粒子群算法AEPSO+动态周期调节灰色模型,深度解析+性能实测
目录 1.摘要2.粒子群算法PSO原理3.改进策略4.结果展示5.参考文献6.代码获取7.算法辅导应用定制读者交流 1.摘要 能源数据的科学预测对于能源行业决策和国家经济发展具有重要意义,尤其是短期能源预测,其精度直接影响经济运行效率。为了更好地提高预测模型…...

