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

MVVM架构下SettingsFragment选CSV传数据到ChartFragment绘图实现咨询

解决方案
  • 第一步:补全ChartViewModel实现
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class ChartViewModel : ViewModel() {
    // 存储CSV解析后的行数据
    val csvResultLiveData = MutableLiveData<List<String>>()
}
  • 第二步:修改SettingsFragment逻辑
    现有代码存在3个问题:
  1. 使用startActivity无法获取文件选择结果,需改用Activity Result API
  2. ViewModel使用by viewModels()获取的是Fragment局部实例,无法和ChartFragment共享,需改为by activityViewModels()获取Activity全局共享实例
  3. 文件选择未限定CSV格式,需添加MIME类型限制
    修改后的完整代码:
import androidx.activity.result.contract.ActivityResultContracts

class SettingsFragment : PreferenceFragmentCompat() {
    private val SETTINGS_DEBUG = "SETTINGS_DEBUG"
    private val resolver by lazy { requireContext().contentResolver }
    // 改为获取Activity范围的共享ViewModel
    private val myViewModel by activityViewModels<ChartViewModel>()

    // 注册文件选择结果回调
    private val pickCsvLauncher = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
        uri ?: return@registerForActivityResult
        // 读取选中的CSV文件内容
        val csvLines = mutableListOf<String>()
        try {
            resolver.openInputStream(uri)?.use { inputStream ->
                inputStream.bufferedReader().useLines { lines ->
                    csvLines.addAll(lines)
                }
            }
            // 过滤空行后发送到ViewModel
            myViewModel.csvResultLiveData.postValue(csvLines.filter { it.isNotBlank() })
        } catch (exc: Exception) {
            Log.d(SETTINGS_DEBUG, "读取CSV文件失败: ${exc.message}")
        }
    }

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey)

        val myPref: Preference? = findPreference("load_csv_file") as Preference?
        myPref?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
            try {
                // 限定仅选择CSV格式文件
                pickCsvLauncher.launch(arrayOf("text/csv", "text/comma-separated-values"))
            } catch (exc: Exception) {
                Log.d(SETTINGS_DEBUG, exc.message.toString())
            }
            true
        }
    }
}
  • 第三步:优化ChartFragment异常兼容
    现有CSV解析逻辑未做异常捕获,遇到格式错误的行会直接崩溃,优化toEntry方法:
private fun toEntry(line: String): Entry? {
    return try {
        val split = line.split(";")
        if (split.size < 3) return null
        val time = split[1]
        val secondsStartIdx = time.length - 2
        val minutesStartIdx = time.length - 4
        val hoursStartIdx = (time.length - 6).coerceAtLeast(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()
        Entry(newTime, split[2].toFloat())
    } catch (e: Exception) {
        Log.d(CHART_DEBUG, "解析行失败: $line, 错误: ${e.message}")
        null
    }
}

对应修改观察者里的转换逻辑:

val newEntries = csvLines.mapNotNull { line -> toEntry(line) }
    .groupingBy { entry -> entry.x }
    .reduce { _, accumulator, element -> if (accumulator.y > element.y) accumulator else element }.values

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:54:05