如何用MPAndroidChart展示Firestore数据库的饼图与折线图
解决Firestore数据映射到MPAndroidChart的问题
核心逻辑说明
Firestore查询是异步操作,必须在数据回调完成后再构建图表数据,不能在初始化时直接同步赋值。下面分饼图和折线图分别给出实现步骤:
1. PieChart(饼图)数据映射
假设你的Firestore数据结构如下(若结构不同,对应调整字段名即可):
集合名:
pieChartData
每个文档字段:category(字符串,如"餐饮")、amount(数值,如120)
代码实现
// 初始化PieChart(保留你现有初始化代码即可) val pieChart = findViewById<PieChart>(R.id.pieChart) pieChart.setUsePercentValues(true) pieChart.description.isEnabled = false // 查询Firestore数据并构建PieEntry列表 val db = FirebaseFirestore.getInstance() db.collection("pieChartData") .get() .addOnSuccessListener { querySnapshot -> val pieEntries = mutableListOf<PieEntry>() for (document in querySnapshot) { // 从文档中取出字段值,字段名需与Firestore完全一致(大小写敏感) val category = document.getString("category") ?: "" val amount = document.getDouble("amount") ?: 0.0 // 创建PieEntry:第一个参数是数值,第二个是分类标签 pieEntries.add(PieEntry(amount.toFloat(), category)) } // 构建PieDataSet与PieData val dataSet = PieDataSet(pieEntries, "消费分类") dataSet.colors = ColorTemplate.MATERIAL_COLORS // 用内置颜色模板 val pieData = PieData(dataSet) pieData.setValueTextSize(12f) pieData.setValueFormatter(PercentFormatter(pieChart)) // 显示百分比格式 // 给饼图赋值并刷新 pieChart.data = pieData pieChart.invalidate() } .addOnFailureListener { exception -> // 处理查询失败,比如打印日志 Log.e("FirestoreError", "饼图数据查询失败", exception) }
2. LineChart(折线图)数据映射
假设你的Firestore数据结构如下:
集合名:
lineChartData
每个文档字段:recordDate(Timestamp类型,记录日期)、dailyCount(数值,如50)
代码实现
// 初始化LineChart(保留你现有初始化代码即可) val lineChart = findViewById<LineChart>(R.id.lineChart) lineChart.description.isEnabled = false lineChart.xAxis.position = XAxis.XAxisPosition.BOTTOM lineChart.axisRight.isEnabled = false // 查询Firestore数据,按日期排序(折线图需有序数据) val db = FirebaseFirestore.getInstance() db.collection("lineChartData") .orderBy("recordDate", Query.Direction.ASCENDING) .get() .addOnSuccessListener { querySnapshot -> val lineEntries = mutableListOf<Entry>() var index = 0f // 用索引作为X轴(简单直接),也可以用时间戳转换为float for (document in querySnapshot) { val dailyCount = document.getDouble("dailyCount") ?: 0.0 // 构建Entry:X轴用索引,Y轴用统计数值 lineEntries.add(Entry(index, dailyCount.toFloat())) index += 1f // 若需用真实日期作为X轴,替换上面的代码: // val timestamp = document.getTimestamp("recordDate")?.toDate()?.time?.toFloat() ?: 0f // lineEntries.add(Entry(timestamp, dailyCount.toFloat())) } // 构建LineDataSet与LineData val dataSet = LineDataSet(lineEntries, "每日统计") dataSet.color = Color.BLUE dataSet.setDrawCircles(true) dataSet.setDrawValues(true) val lineData = LineData(dataSet) // 若用时间戳作为X轴,需自定义格式化器显示日期: // lineChart.xAxis.valueFormatter = object : ValueFormatter() { // override fun getFormattedValue(value: Float): String { // val sdf = SimpleDateFormat("MM-dd", Locale.getDefault()) // return sdf.format(Date(value.toLong())) // } // } // 给折线图赋值并刷新 lineChart.data = lineData lineChart.invalidate() } .addOnFailureListener { exception -> Log.e("FirestoreError", "折线图数据查询失败", exception) }
常见问题排查
- 字段名不匹配:Firestore字段名与代码中
getString/getDouble的参数必须完全一致(大小写敏感)。 - 数据类型不匹配:比如Firestore存的是Long类型,代码用
getDouble会返回null,需对应使用getLong。 - 异步时机错误:必须在
addOnSuccessListener内部处理数据,不能在回调外构建图表(此时数据还未返回)。 - 空值处理:用
?:给字段设置默认值,避免空指针异常。
内容的提问来源于stack exchange,提问作者teachmetocode
相关产品推荐
相关产品推荐

