开源图表库选型:MPAndroidChart 之外还有什么
开源图表库选型:MPAndroidChart 之外还有什么
MPAndroidChart 在 GitHub 上有着超过三万六千个 Star,这让它几乎成了 Android 图表领域的默认答案。但如果你在 2024 年打开它的 release 页面,看到的最新稳定版本仍然是 2019 年发布的 v3.1.0。过去五年间,Android 系统经历了 Jetpack Compose 的全面推广、Target SDK 对后台行为的严格收紧、以及 Material You 动态色彩的普及,而这个库的核心架构几乎停留在原地。社区里堆积了两千多个 open issue,从 RecyclerView 中的内存泄漏到高 DPI 屏幕下的像素对齐问题,很多修复代码躺在 PR 列表里无人合并。这不是在否定它的历史地位,而是想说:对于新项目而言,把 MPAndroidChart 作为唯一备选,已经不是一个经过深思熟虑的技术决策,而是一种路径依赖。
MPAndroidChart 的遗产与包袱
这个库的设计语言深深烙刻着 2015 年左右的 Android 开发范式。它基于 View 系统,核心模型由 Entry、DataSet、Chart 三层构成,所有配置都通过 setter 方法链完成。这种设计在当年非常先进,因为它把图表拆成了可组合的数据层和渲染层。但放到今天来看,这套 API 显得过于冗长。你想改一个柱状图的圆角?大概率需要继承 BarChartRenderer,重写 drawDataSet 方法,在里面操作 Canvas 和 Paint。你想在折线图下方加渐变填充?要去研究 LineDataSet 的 setDrawFilled(true) 以及它背后那个并不直观的 Drawable 填充逻辑。
更让人头疼的是它在现代 Android 上的兼容成本。MPAndroidChart 没有官方 Jetpack Compose 支持,在 Compose 项目中你必须用 AndroidView 包装,这带来一系列重组(recomposition)时的状态同步问题。Chart 的 highlight 状态、动画进度、以及触摸事件,都很难与 Compose 的 State 无缝衔接。此外,这个库在 RecyclerView 的 ViewHolder 复用场景下一直有内存泄漏的隐患,如果你没有在 onViewRecycled 里手动调用 chart.clear() 并清空 data,很容易在滑动时看到 GC 频繁触发。到了 Android 14,系统对后台绘制线程的限制变得更严格,MPAndroidChart 里一些基于 Handler 的动画定时器偶尔会在特定机型上触发 FrameMetrics 的警告。这些问题并非不可解决,但解决的代价是你要深入它那一套庞大的 Java 继承体系,而社区已经没人保证你改完不会破坏其他地方。
Vico:Kotlin 优先的新思路
如果你在寻找一个从底层就为现代 Android 设计的图表库,Vico 是目前最值得关注的选项之一。它是由 patrykandpatrick 维护的开源项目,底层用 Kotlin 重写,同时兼容传统 View 系统和 Jetpack Compose。它的 GitHub 地址很直白:github.com/patrykandpatrick/vico,协议是 Apache 2.0,可以直接商用。
Vico 的 API 设计抛弃了 MPAndroidChart 那种厚重的 OOP 继承链,转而采用声明式风格。以 Compose 为例,你定义一个折线图,本质上是在写一个可组合函数,通过 ChartStyle 和 AxisValueFormatter 的 lambda 来控制外观。它的坐标轴、图例、标记点(Marker)都被抽象成了独立的 Component,彼此通过 Measurement 和绘制阶段解耦。这种分层在定制十字线(crosshair)时特别舒服,你只需要提供一个 MarkerComponent,库会自动处理它与数据点的吸附和对齐,不需要像 MPAndroidChart 那样去监听 OnChartValueSelectedListener 再手动算坐标。
我个人比较认可的是它的动画系统。Vico 的入场动画基于 Android 的 Animator,但包装了一层更贴合图表语义的 API,比如 lineSpec 的 drawingModel 可以让你控制折线是从左到右展开,还是整体淡入。这在 MPAndroidChart 里通常需要拿到 Animator 实例再自己补间,而在 Vico 里属于一等公民。
不过,选 Vico 也要做好面对它年轻