Android Studio中如何将Firestore数据加载至MPChart(柱状图、饼图)
I see you already have a working setup with mock data for your LineChart and BarChart. Let's convert that to pull real data from Firestore, and we'll add the PieChart implementation too. Here's a step-by-step solution:
Step 1: Define Your Firestore Data Structure
First, make sure your Firestore collection is structured to hold weekly income data tied to the authenticated user. For example, create a collection named weeklyIncomes where each document has:
day: String (e.g. "Sunday", "Monday")income: Number (integer value of the day's income)userId: String (matches the current user's UID from Firebase Auth)
Step 2: Update the Fragment Code to Fetch Firestore Data
We'll replace your mock data method with Firestore's asynchronous data fetch, and add the PieChart logic. Here's the updated StatisticFragment code:
public class StatisticFragment extends Fragment { FirebaseAuth fAuth; FirebaseFirestore db; String userID; LineChart lineChart; LineData lineData; LineDataSet lineDataSet; ArrayList lineEntries; BarChart weeklyIncomeBarchart; PieChart weeklyIncomePieChart; // Added PieChart ArrayList<BarEntry> barEntryArrayList; ArrayList<String> labelsName; ArrayList<WeeklyIncomeChart> weeklyIncomeCharts = new ArrayList<>(); ArrayList<PieEntry> pieEntryArrayList; // For PieChart @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_statistic, container, false); getActivity().setTitle("Statistic"); fAuth = FirebaseAuth.getInstance(); db = FirebaseFirestore.getInstance(); userID = fAuth.getCurrentUser().getUid(); // Get current user ID // Initialize LineChart (keep your existing mock setup or replace with Firestore data later) lineChart = v.findViewById(R.id.lineChart); getEntries(); lineDataSet = new LineDataSet(lineEntries, ""); lineData = new LineData(lineDataSet); lineChart.setData(lineData); lineDataSet.setColors(ColorTemplate.JOYFUL_COLORS); lineDataSet.setValueTextColor(Color.BLACK); lineDataSet.setValueTextSize(18f); // Initialize BarChart and PieChart weeklyIncomeBarchart = v.findViewById(R.id.weeklyIncomeBarchart); weeklyIncomePieChart = v.findViewById(R.id.weeklyIncomePieChart); // Initialize PieChart barEntryArrayList = new ArrayList<>(); labelsName = new ArrayList<>(); pieEntryArrayList = new ArrayList<>(); // Fetch data from Firestore and update charts fetchWeeklyIncomeFromFirestore(); return v; } // Keep your existing LineChart mock data method for now private void getEntries() { lineEntries = new ArrayList<>(); lineEntries.add(new Entry(2f, 0)); lineEntries.add(new Entry(4f, 1)); lineEntries.add(new Entry(6f, 1)); lineEntries.add(new Entry(8f, 3)); lineEntries.add(new Entry(7f, 4)); lineEntries.add(new Entry(3f, 3)); } // Replace mock fill method with Firestore fetch private void fetchWeeklyIncomeFromFirestore() { weeklyIncomeCharts.clear(); barEntryArrayList.clear(); labelsName.clear(); pieEntryArrayList.clear(); // Query Firestore for current user's weekly income data db.collection("weeklyIncomes") .whereEqualTo("userId", userID) .get() .addOnSuccessListener(queryDocumentSnapshots -> { for (DocumentSnapshot document : queryDocumentSnapshots) { // Map document to your WeeklyIncomeChart model WeeklyIncomeChart incomeData = document.toObject(WeeklyIncomeChart.class); weeklyIncomeCharts.add(incomeData); // Prepare data for BarChart String day = incomeData.getDays(); int income = incomeData.getIncome(); labelsName.add(day); barEntryArrayList.add(new BarEntry(labelsName.size()-1, income)); // Prepare data for PieChart pieEntryArrayList.add(new PieEntry(income, day)); } // Update BarChart updateBarChart(); // Update PieChart updatePieChart(); }) .addOnFailureListener(e -> { // Handle error (e.g., show toast) Toast.makeText(getContext(), "Failed to load data: " + e.getMessage(), Toast.LENGTH_SHORT).show(); }); } private void updateBarChart() { BarDataSet barDataSet = new BarDataSet(barEntryArrayList, "Days"); barDataSet.setColors(ColorTemplate.COLORFUL_COLORS); Description description = new Description(); description.setText("Weekly Income"); weeklyIncomeBarchart.setDescription(description); BarData barData = new BarData(barDataSet); weeklyIncomeBarchart.setData(barData); // Configure XAxis (keep your existing setup) XAxis xAxis = weeklyIncomeBarchart.getXAxis(); xAxis.setValueFormatter(new IndexAxisValueFormatter(labelsName)); xAxis.setPosition(XAxis.XAxisPosition.TOP); xAxis.setDrawGridLines(false); xAxis.setDrawAxisLine(false); xAxis.setGranularity(1f); xAxis.setLabelCount(labelsName.size()); xAxis.setLabelRotationAngle(270); weeklyIncomeBarchart.animateY(2000); weeklyIncomeBarchart.invalidate(); // Refresh chart } private void updatePieChart() { PieDataSet pieDataSet = new PieDataSet(pieEntryArrayList, "Weekly Income Distribution"); pieDataSet.setColors(ColorTemplate.MATERIAL_COLORS); pieDataSet.setValueTextColor(Color.BLACK); pieDataSet.setValueTextSize(14f); PieData pieData = new PieData(pieDataSet); weeklyIncomePieChart.setData(pieData); weeklyIncomePieChart.setDescription(new Description()); // Hide default description weeklyIncomePieChart.setCenterText("Weekly Income"); weeklyIncomePieChart.animateY(1500); weeklyIncomePieChart.invalidate(); // Refresh chart } }
Step 3: Update the Layout XML to Include PieChart
Add the PieChart widget below your BarChart in fragment_statistic.xml (we also added a ScrollView to handle overflow):
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_green_light"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <com.github.mikephil.charting.charts.LineChart android:id="@+id/lineChart" android:layout_width="match_parent" android:layout_height="200dp" /> <com.github.mikephil.charting.charts.BarChart android:id="@+id/weeklyIncomeBarchart" android:layout_width="match_parent" android:layout_height="250dp" android:layout_marginTop="20dp" android:layout_below="@+id/lineChart"/> <!-- Added PieChart --> <com.github.mikephil.charting.charts.PieChart android:id="@+id/weeklyIncomePieChart" android:layout_width="match_parent" android:layout_height="250dp" android:layout_marginTop="20dp" android:layout_below="@+id/weeklyIncomeBarchart"/> </RelativeLayout> </ScrollView> </FrameLayout>
Key Points to Note
- Asynchronous Data Fetch: Firestore operations are async, so we update the charts only inside the
onSuccess()callback once data is retrieved. - Model Class Compatibility: Ensure your
WeeklyIncomeChartclass has a no-argument constructor and public getters fordaysandincomeso Firestore can map the document data to it. - Error Handling: We added a
onFailure()listener to handle cases where data fetch fails (e.g., network issues). - Chart Refresh: Always call
invalidate()after updating chart data to force the UI to refresh.
内容的提问来源于stack exchange,提问作者Muhammad Pauzi

