开源图表库选型:MPAndroidChart 之外还有什么
开源图表库选型:MPAndroidChart 之外还有什么
一个被反复问到的老问题
去年维护的一个企业级项目里,产品突然要求在报表页加一套复杂的组合图表:柱状图叠折线图,带自定义 marker,还要支持手势联动。团队里有人直接甩了 MPAndroidChart,说"这个最成熟,GitHub 星最多"。我拉了下依赖,最新 release 还是 2020 年的 v3.1.0,仓库里 400 多个 open issue 没人理,PR 也堆了三年。这不是个例,MPAndroidChart 的维护停滞已经是社区共识,但很多人选型时还是惯性思维先想到它。
这篇文章不是做排行榜,而是基于我实际集成和踩坑的经历,聊聊几个真正值得关注的替代方案。有些你可能听过但没深入看过,有些可能完全陌生。重点放在 Android 原生场景,也会涉及跨平台选项,但会明确标出边界。
MPAndroidChart 的真实现状
先把这个"标杆"说清楚。MPAndroidChart 的作者 Philipp Jahoda 早年确实做出了非常全面的功能集合:线形图、柱状图、饼图、雷达图、K 线图、散点图,自定义动画、手势缩放、高亮选中,几乎覆盖了移动端图表的所有常规需求。代码结构也很直观,继承体系清晰,新手改个颜色、换个字体半天就能上手。
问题出在维护层面。2020 年之后作者基本淡出,仓库进入事实上的 archive 状态。社区 fork 出了几个分支,比如 MPAndroidChart-Realm 试图对接 Realm 数据库,但也都凉得差不多。现在如果你去集成,大概率会遇到这些情况:targetSdk 34 的兼容性警告、Android 12 以上的手势冲突、Jetpack Compose 环境下无法直接复用、某些机型上的硬件加速渲染异常。这些问题在 issue 列表里都有记录,但没人修。
更隐蔽的问题是性能。MPAndroidChart 的绘制基于 Canvas 的即时模式,数据量上千个点就开始掉帧,万级别直接卡死。它也没有现代图表库常见的脏矩形优化或分层渲染策略,每次手势交互都要重绘整个图表区域。我做过一次 profiling,一个 2000 点的折线图,缩放时 GPU 帧时间飙到 30ms+,明显超过 16.6ms 的 60fps 预算。
所以结论很明确:新项目不建议再用,老项目如果功能稳定且没有维护需求,可以暂时不动,但要有迁移的心理准备。
HelloCharts:一个被低估的轻量选项
HelloCharts 是另一个历史比较久的库,作者 Leszek Wach 的仓库地址是 github.com/lecho/hellocharts-android。它最大的特点是 API 设计极其克制,整个库的体积比 MPAndroidChart 小一半还多,核心就一个 module,没有复杂的依赖树。
我 2021 年在一个 IoT 设备配套 App 里用过它。那个项目对包体积敏感,APK 不能超过 15MB,而且图表需求很基础:温度曲线的实时刷新,24 小时历史回看,加上简单的极值标注。HelloCharts 的 LineChartView 直接满足,集成代码不到 100 行。它的动画系统做得比 MPAndroidChart 流畅,数据更新时默认有平滑过渡,不需要手动插值。
但这个库的局限也很致命。功能集比 MPAndroidChart 窄很多,没有组合图表,没有 CandleStick,雷达图也没有。自定义空间被刻意限制,比如你想改 Y 轴的网格线样式,只能调颜色和粗细,不能自定义绘制逻辑。作者 2018 年后也基本停更,最后一次 commit 是适配 AndroidX 的迁移。
我的判断是:如果你的需求在库提供的功能范围内,且对体积和启动速度有硬性要求,HelloCharts 仍然可用。但别指望扩展,它的架构就不是为扩展设计的。仓库的 issue 区有人问过 Compose 支持,作者明确回复不会跟进,这也划清了它的适用边界。
WilliamChart:动画优先的另类选择
Diogo Bernardino 的 WilliamChart 是个很有意思的项目,github.com/diogobernardino/williamchart。它的设计理念和前面两个完全不同:不追求功能全面,而是把动画表现力做到极致。库里的每种图表都有精心设计的入场和交互动画,比如柱状图从底部弹性生长,折线图的点逐个浮现带涟漪效果。
这个库我在一个消费级 App 的 onboarding 流程里用过,需要展示用户的首周数据概览,产品强调"情感化设计"。WilliamChart 的动画参数可调得很细,duration、delay、easing function 都能配,甚至能接物理动画的 spring 效果。代码层面它用了属性动画系统,没有自己造轮子,兼容性和性能都不错。
代价是功能阉割。它只支持四种图表:LineChart、BarChart、HorizontalBarChart、DonutChart。没有 PieChart(只有 Donut),没有组合图表,没有手势交互,点击高亮都要自己写 listener 再重绘。数据绑定方式也比较原始,没有 adapter 模式,直接塞 float 数组。
还有一个坑是它的坐标轴系统。Y 轴的刻度计算是自动的,但算法比较粗糙,遇到数据范围不规则时会出现 0.003 这种难看的步长,而且没法强制指定 tick 值。我最后是通过预处理数据,手动对齐到整数刻度,再隐藏默认 Y 轴、自己用 Canvas 画了一套替代。
WilliamChart 的维护状态比前两个稍好,作者 2022 年还有过更新,但频率很低。我的建议是:把它当成"动画素材库"来用,适合展示型场景,不适合分析型场景。如果产品要的是"好看的数据动效",它是 Android 原生方案里数一数二的选择;如果要的是"灵活的数据探索工具",直接跳过。
AAChartCore-Kotlin:跨平台思维的原生实现
这个库可能很多人没听过,但它背后有个更知名的前身:AAChartCore 的 Swift 版本在 iOS 社区有一定知名度。Kotlin 移植版的仓库是 github.com/AAChartModel/AAChartCore-Kotlin,作者 An An 维护得比较积极,最近几个月还有 commit。
AAChartCore-Kotlin 的核心思路很独特:它不做自研渲染,而是封装了 WebView + JavaScript 图表库(底层是 Highcharts 和 ECharts 的精简版)。你在 Kotlin 层配置图表参数,库自动生成对应的 JS 代码,注入到 WebView 里执行。这意味着它的功能上限直接继承了 Web 图表生态,3D 图、桑基图、热力图、地图这些移动端原生库很难做的东西,它都能直接调。
我在一个金融数据 App 里评估过这个方案。产品要 K 线 + 成交量 + MACD 的三图联动,还要画斐波那契回调线。原生库里面,MPAndroidChart 的 CandleStick 实现有 bug,WilliamChart 没有 K 线,HelloCharts 更是完全不沾边。AAChartCore-Kotlin 通过 JS 层直接调 Highstock 的解决方案,两周就出了 demo,效果很完整。
但 WebView 方案的坑也很多。首先是内存,每个图表实例都是一个独立 WebView,十个图表同时存在时内存占用轻松过 200MB。其次是初始化延迟,WebView 首次创建要 300-500ms,即使做了预加载,图表渲染还是比原生慢半拍。最严重的是手势冲突,WebView 内部的滚动和缩放与外层 Native 列表的滑动经常打架,需要写复杂的 TouchDelegate 分发逻辑。
还有一个授权隐患。Highcharts 是商业软件,免费版有水印且功能受限,AAChartCore-Kotlin 默认用的是 Highcharts 的社区精简版,但文档里对授权边界说得模糊。我发邮件问过作者,回复说"个人和非商业项目可用,企业建议购买 Highcharts 授权"。这个灰色地带让很多公司法务直接否决了这个选项。
最终那个金融项目没有采用 AAChartCore-Kotlin,但它的思路给了我很大启发:当原生图表库的能力边界被触及时, hybrid 方案是条可行路径,只是要算清楚性能、授权、维护的账。
Vico:Jetpack Compose 时代的原生答案
如果说前面几个都是"前 Compose 时代"的遗产,Vico 就是专门为 Compose 设计的现代图表库。仓库在 github.com/patrykandpatrick/vico,作者 Patryk Goworowski 和 Patrick Michalik 从 2022 年开始持续迭代,目前最新稳定版是 1.14.0,发布节奏很健康。
Vico 的架构完全围绕 Compose 的声明式范式重构。没有 View 体系,没有 findViewById,图表就是一个 Composable 函数,数据通过 State 驱动,动画用 Compose 自带的 AnimatedVisibility 和 animate*AsState 实现。这个设计让它在 Compose 项目里的集成体验远超所有老库。
我 2023 年把一个小项目的图表模块从 MPAndroidChart 迁移到 Vico,代码量减少了 40%。最爽的是主题适配:Compose 的 MaterialTheme 直接透传到图表内部,动态换色不需要手动同步。Vico 的 ColumnChart 和 LineChart 支持共享 X 轴的滚动联动,实现方式是把多个图表包在一个共同的 ChartScrollState 里,比 MPAndroidChart 的联动监听器简洁得多。
功能层面,Vico 目前支持 ColumnChart、LineChart、ComposedChart(组合图)、PieChart、CandleStickChart。组合图的实现很干净,可以把 ColumnChart 和 LineChart 的 spec 直接拼在一起,不需要像 MPAndroidChart 那样继承特定的 CombinedData 类。Marker 的自定义也用了 Compose 的 slot API,你可以传一个 Composable 进去作为弹窗内容,完全自由。
性能方面,Vico 用了 Compose 的 LazyList 类似的按需渲染策略,可视区域外的数据点不会参与绘制。我测试过 5000 个点的折线图,缩放时帧时间稳定在 8-10ms,比 MPAndroidChart 同场景快三倍。但这里有个前提:你必须用 Compose 的 remember 正确缓存数据,如果每次数据更新都重新生成整个 ChartModel,性能优势就没了。
Vico 的坑主要在版本迭代速度上。1.x 系列的 API 变动比较频繁,我集成时用的 1.9.0,升到 1.12.0 时 ChartStyle 的构造方式变了,需要改十几处代码。作者文档里会标 breaking changes,但迁移成本客观存在。另外它的 PieChart 功能相对薄弱,不支持环形图的厚度渐变,也不支持扇区的分离动画,复杂饼图需求可能不够。
还有一个隐藏限制:Vico 要求 minSdk 21,对老旧设备不支持。以及它完全绑定 Compose,传统 View 体系的项目没法直接用,必须套一个 ComposeView,这会带来一定的互操作开销。
Compose Charts 与官方方向的空白
Google 官方在 Compose 的 material-components 仓库里曾经有个 charts 子模块的实验,但 2023 年被正式砍掉,官方声明说"短期内没有提供图表组件的计划"。这个决定让很多开发者失望,但也留下了生态空间给第三方库。
市面上还有几个 Compose 专用的轻量图表库,比如 github.com/jaikeerthick/Composable-Graphs,功能极简,只有 LineChart 和 BarChart,适合快速原型。还有 github.com/madrapps/plot,API 设计很函数式,但文档缺失严重,我尝试集成时连基本的坐标轴标签配置都找了半天。
这些库的共同问题是维护不稳定,作者通常是个人开发者,项目热度过了就弃坑。相比之下 Vico 的双作者模式和持续发布节奏更值得信赖,这也是我目前 Compose 项目的默认选择。
跨平台选项的边界:Compose Multiplatform 和 KMP
如果项目本身用 Compose Multiplatform,图表选型会更复杂。Vico 目前只支持 Android,没有 KMP 的 common 模块。AAChartCore-Kotlin 理论上可以跑在 iOS 的 WebView 上,但实际没人验证过。
这里有个折中方案:github.com/KoalaPlot/koalaplot,专门为 KMP 设计的图表库,支持 Android、Desktop、iOS(通过 Compose for iOS)。作者 Steve Grotz 的更新频率中等,功能集包括 LineChart、BarChart、PieChart、RadarChart,比 Vico 少但比 HelloCharts 多。
我 2024 年初在一个 KMP 实验项目里试过 KoalaPlot。API 设计很 Kotlin-idiomatic,用 DSL 配图表结构,数据类直接映射。但性能明显比 Vico 差,Desktop 端 1000 个点就开始掉帧,iOS 端的文本渲染还有模糊问题。作者回复说 iOS 的 skiko 文本后端还在优化,建议暂时用自定义 font 规避。
KoalaPlot 的当前版本是 0.5.3,API 还在剧烈变动中,文档标注为"pre-release",生产环境慎用。它的价值在于证明了 KMP 图表的可行性,但距离成熟还有距离。我的建议是:纯 Android 项目不必为了跨平台潜力选它,真正的 KMP 项目可以评估,但要预留性能调优和 bug 修复的时间。
一个被忽略的领域:自研渲染
当所有现成库都不满足时,最后的选项是自研。这不是说从头写一套完整的图表系统,而是基于 Canvas 或 OpenGL 做针对性实现。
我 2022 年参与过一个医疗影像项目,需要在实时波形图上叠加阈值告警线和异常标记,同时保证 60fps 的刷新率。评估了所有开源库后,发现它们的渲染管线都无法满足"部分区域高频更新、其他区域静态"的需求。最终方案是基于 Android 的 SurfaceView 做双缓冲,Y 轴网格和背景预渲染到 Bitmap 缓存,实时数据用 Path 直接画在 front buffer,GPU 合成。
这个方案的开发周期三周,代码量 3000 行左右,但性能远超任何开源库。关键洞见是:图表库为了通用性,渲染管线必然有 overhead;当需求足够聚焦时,自研的 ROI 可能更高。
自研的门槛在降低。Android 的 Graphics 层近年新增了 AGSL(Android Graphics Shading Language)和 RenderEffect,可以实现以前需要 OpenGL ES 的着色器效果。Jetpack 的 graphics-core 库也在推进更底层的 GPU 访问。这些工具让"半自研"成为可能:用开源库处理坐标计算和手势,自己接管最终绘制。
选型的决策框架
聊了这么多具体库,最后给一个我做选型时的思考顺序,供参考。
第一步明确渲染层。Compose 项目优先考虑 Vico,传统 View 项目看功能复杂度选 HelloCharts(简单)或 WilliamChart(动画),必须跨平台且能接受 WebView 开销的看 AAChartCore-Kotlin,KMP 实验项目评估 KoalaPlot。
第二步验证维护状态。拉仓库的 commit 历史,看最近三个月是否有实质性更新;看 issue 的回复率,作者是否活跃;看 release note 的 breaking change 频率,判断升级成本。
第三步做性能基准测试。用真实数据量(不是 demo 里的 12 个月份)跑 profile,关注手势交互时的帧时间、内存抖动、GC 频率。这个环节不能省,很多库的 demo 看着流畅,上真实数据就崩。
第四步检查授权合规。特别是包含 JS 运行时或商业图表引擎的库,要和法务确认授权边界。AAChartCore-Kotlin 的 Highcharts 依赖、MPAndroidChart 的 Apache 2.0 都是容易踩坑的点。
第五步预留迁移路径。即使选了最满意的库,也要抽象一层 Repository 接口,避免业务代码直接依赖具体图表实现。这个防御性设计在库停更或需求变更时能救命。
一些具体的版本和链接
写到这里,把提到的库整理一下,方便直接查找:
MPAndroidChart:github.com/PhilJay/MPAndroidChart,v3.1.0(2020),Apache 2.0
HelloCharts:github.com/lecho/hellocharts-android,last commit 2018,Apache 2.0
WilliamChart:github.com/diogobernardino/williamchart,v3.10.1(2022),Apache 2.0
AAChartCore-Kotlin:github.com/AAChartModel/AAChartCore-Kotlin,v1.0.0(持续更新),MIT(但底层 Highcharts 授权另计)
Vico:github.com/patrykandpatrick/vico,v1.14.0(2024),Apache 2.0
KoalaPlot:github.com/KoalaPlot/koalaplot,v0.5.3(pre-release),MIT
Composable-Graphs:github.com/jaikeerthick/Composable-Graphs,v1.0.0,Apache 2.0
最后的个人倾向
如果今天新开一个 Android 项目,我的默认选择是 Vico。Compose 已经是 UI 开发的事实标准,Vico 的架构契合度、维护活跃度、功能完备性在当前生态里没有明显对手。它的 API 变动问题可以通过锁版本缓解,等 2.0 稳定后再迁移。
传统 View 体系的遗留项目,如果图表需求不复杂且没有 Compose 迁移计划,HelloCharts 仍然是最省心的轻量选项。但要有心理准备,它不会再进化。
AAChartCore-Kotlin 我会保持关注,不是因为推荐现在用,而是它的 hybrid 思路代表了移动端图表的一个可能方向。如果未来 WebAssembly 在 Android 上成熟,或者官方提供更低 overhead 的 JS 运行时,这类方案的性能瓶颈可能被打破。
自研渲染永远是最后的底牌,但不要过早打出。大多数团队的图表需求远没有独特到需要自定义渲染管线的程度,先把现成的用好、理解其边界,再决定要不要造轮子。
MPAndroidChart 的时代确实过去了,但"之外还有什么"这个问题,答案取决于你的技术栈、产品需求和团队约束。没有银弹,只有权衡。