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

如何将单Activity的CSV绘图代码迁移适配到Drawer导航的Fragment架构

Android CSV图表功能Fragment架构迁移适配方案

原有应用逻辑为点击按钮唤起文件选择窗口,选中CSV文件后读取数据绘制到图表上,现适配基于Fragment的导航架构的迁移步骤如下:

1. 调整布局文件fragment_chart.xml

将原有activity_main.xml中的按钮和图表控件迁移到fragment_chart.xml中,保持控件id不变:

  • 加载CSV按钮id:R.id.button_loadCsv
  • 折线图控件id:R.id.lineChart

2. 修改ChartViewModel.kt

增加图表数据的存储和观察能力,修改后代码如下:

package com.example.aplikacjadlataty.ui.chart

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.github.mikephil.charting.data.Entry

class ChartViewModel : ViewModel() {
    private val _chartEntries = MutableLiveData<List<Entry>>()
    val chartEntries: LiveData<List<Entry>> = _chartEntries

    fun updateChartEntries(entries: List<Entry>) {
        _chartEntries.value = entries
    }
}

3. 重构ChartFragment.kt

将原有MainActivity中的业务逻辑全部迁移到Fragment中,适配Fragment生命周期和上下文调用规则,修改后代码如下:

package com.example.aplikacjadlataty.ui.chart

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
import com.example.aplikacjadlataty.R
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.animation.Easing
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.Collections

class ChartFragment : Fragment() {

    private lateinit var chartViewModel: ChartViewModel
    private lateinit var lineChart: LineChart

    private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
        uri ?: return@registerForActivityResult
        val lines = readCSV(uri)
        val newEntries = lines.map { line -> toEntry(line) }
            .groupingBy { entry -> entry.x }
            .reduce { _, accumulator, element ->
                if (accumulator.y > element.y) accumulator else element
            }.values
        chartViewModel.updateChartEntries(newEntries.toList())
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        chartViewModel = ViewModelProviders.of(this).get(ChartViewModel::class.java)
        val root = inflater.inflate(R.layout.fragment_chart, container, false)

        lineChart = root.findViewById(R.id.lineChart)
        val loadCsvBtn = root.findViewById<Button>(R.id.button_loadCsv)

        initChartBaseConfig()
        loadCsvBtn.setOnClickListener {
            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            intent.type = "text/*"
            getContent.launch("text/*")
        }

        chartViewModel.chartEntries.observe(viewLifecycleOwner) { entries ->
            refreshChart(entries)
        }
        return root
    }

    private fun initChartBaseConfig() {
        lineChart.apply {
            description.isEnabled = false
            isHighlightPerDragEnabled = false
            isScaleYEnabled = false
            axisRight.isEnabled = false
            marker = CustomMarker(requireContext(), R.layout.marker_view)
        }
    }

    private fun refreshChart(entries: List<Entry>) {
        val vl = LineDataSet(entries.take(4000), "cost")
        vl.apply {
            setDrawValues(false)
            setDrawFilled(true)
            lineWidth = 1.5f
            fillColor = R.color.gray
            fillAlpha = R.color.red
            setDrawCircles(false)
        }
        lineChart.data = LineData(vl)
        lineChart.notifyDataSetChanged()
        lineChart.animateX(1800, Easing.EaseInExpo)
    }

    @Throws(IOException::class)
    private fun readCSV(uri: Uri): List<String> {
        val csvFile = requireContext().contentResolver.openInputStream(uri) ?: return Collections.emptyList()
        val isr = InputStreamReader(csvFile)
        return BufferedReader(isr).readLines()
    }

    private fun toEntry(line: String): Entry {
        val split = line.split(";")
        val time = split[1]
        val secondsStartIdx = time.length - 2
        val minutesStartIdx = time.length - 4
        val hoursStartIdx = Math.max(time.length - 6, 0)

        val hour = time.substring(hoursStartIdx, hoursStartIdx + time.length - 4)
        val minutest = time.substring(minutesStartIdx, minutesStartIdx + 2)
        val seconds = time.substring(secondsStartIdx, secondsStartIdx + 2)

        val newTime =
            hour.toFloat() * 10000 + (minutest.toFloat() * 100 / 60).toInt() * 100 + (seconds.toFloat() * 100 / 60).toInt()
        return Entry(newTime, split[2].toFloat())
    }
}

4. 保留NavigationActivity.kt无需修改

原有NavigationActivity已经完成了导航架构配置、广告初始化、分享功能等逻辑,且Chart页面已配置为顶层目的地,不需要额外调整。

内容的提问来源于stack exchange,提问作者MaksChojniak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:12:03