You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 04:35:28