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

使用MPAndroidChart绘制安卓实时加速度折线图时触发NegativeArraySizeException

MPAndroidChart实时折线图展示线性加速度抛出NegativeArraySizeException异常

我想用MPAndroidChart制作实时折线图展示安卓手机的线性加速度,但运行时出现了NegativeArraySizeException异常。

实现代码

package com.example.graph_example

import android.content.Context
import android.graphics.Color
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import java.util.Calendar

class MainActivity : AppCompatActivity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private lateinit var linearAccelerationSensor: Sensor
    private lateinit var chart : LineChart
    private lateinit var dataSetX: LineDataSet
    private lateinit var dataSetY: LineDataSet
    private lateinit var dataSetZ: LineDataSet
    private var lastX = 0.0f
    private var lastY = 0.0f
    private var lastZ = 0.0f
    private var timestamp: Long = 0L


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        linearAccelerationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)

        chart = findViewById(R.id.line_chart)

        dataSetX = LineDataSet(mutableListOf(), "X")
        dataSetX.color = Color.RED
        dataSetX.lineWidth = 2.5f
        dataSetX.setDrawValues(false)
        dataSetX.mode = LineDataSet.Mode.CUBIC_BEZIER

        dataSetY = LineDataSet(mutableListOf(), "Y")
        dataSetY.color = Color.GREEN
        dataSetY.lineWidth = 2.5f
        dataSetY.setDrawValues(false)
        dataSetY.mode = LineDataSet.Mode.CUBIC_BEZIER

        dataSetZ = LineDataSet(mutableListOf(), "Z")
        dataSetZ.color = Color.BLUE
        dataSetZ.lineWidth = 2.5f
        dataSetZ.setDrawValues(false)
        dataSetZ.mode = LineDataSet.Mode.CUBIC_BEZIER

        chart.data = LineData(dataSetX, dataSetY, dataSetZ)
        chart.description.isEnabled = false
        chart.legend.isEnabled = false
        chart.setNoDataText("Waiting for data...")
        chart.setNoDataTextColor(Color.BLACK)
        chart.setTouchEnabled(false)
        chart.isDragEnabled = false
        chart.setScaleEnabled(false)
        chart.setPinchZoom(false)
        chart.setDrawGridBackground(false)
        chart.axisRight.isEnabled = false
        chart.xAxis.position = XAxis.XAxisPosition.BOTTOM
        chart.xAxis.setDrawAxisLine(false)

    }

    override fun onResume() {
        super.onResume()
        sensorManager.registerListener(this, linearAccelerationSensor, SensorManager.SENSOR_DELAY_GAME)
    }

    override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
    }

    override fun onSensorChanged(event: SensorEvent?) {
        if (event != null) {
            val x = event.values[0]
            val y = event.values[1]
            val z = event.values[2]

            val currentTime = Calendar.getInstance().timeInMillis
            if (timestamp != 0L) {
                val dt = ((currentTime - timestamp) / 1000.0f)
                val dx = x * dt
                val dy = y * dt
                val dz = z * dt
                // 更新累计值
                lastX += dx
                lastY += dy
                lastZ += dz
                // 添加新数据点,X轴用累计值,Y轴用当前加速度
                val pointX = Entry(lastX, x)
                val pointY = Entry(lastY, y)
                val pointZ = Entry(lastZ, z)
                dataSetX.addEntry(pointX)
                dataSetY.addEntry(pointY)
                dataSetZ.addEntry(pointZ)
                // 通知图表更新
                chart.data.notifyDataChanged()
                chart.notifyDataSetChanged()
                // 限制X轴显示范围
                chart.setVisibleXRangeMaximum(20.0f)
                chart.moveViewToX(lastX)
            }
            // 记录当前时间作为下一次的基准
            timestamp = currentTime
        }
    }


    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
        // Do nothing
    }

}

错误日志

2023-01-02 22:13:27.370 13697-13697/com.example.graph_example E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.graph_example, PID: 13697
    java.lang.NegativeArraySizeException: -12
        at com.github.mikephil.charting.utils.Transformer.generateTransformedValuesLine(Transformer.java:178)
        at com.github.mikephil.charting.renderer.LineChartRenderer.drawValues(LineChartRenderer.java:549)
        at com.github.mikephil.charting.charts.BarLineChartBase.onDraw(BarLineChartBase.java:278)
        at android.view.View.draw(View.java:22350)
        at android.view.View.updateDisplayListIfDirty(View.java:21226)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
        at android.view.View.updateDisplayListIfDirty(View.java:21186)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
        at android.view.View.updateDisplayListIfDirty(View.java:21186)
        at android.view.View.draw(View.java:22081)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
        at android.view.View.updateDisplayListIfDirty(View.java:21217)
        at android.view.View.draw(View.java:22081)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
        at android.view.View.updateDisplayListIfDirty(View.java:21217)
        at android.view.View.draw(View.java:22081)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
        at android.view.View.updateDisplayListIfDirty(View.java:21217)
        at android.view.View.draw(View.java:22081)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4516)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4277)
        at android.view.View.draw(View.java:22353)
        at com.android.internal.policy.DecorView.draw(DecorView.java:806)
        at android.view.View.updateDisplayListIfDirty(View.java:21226)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:559)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:565)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:642)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:4101)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3828)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3099)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1952)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8171)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
        at android.view.Choreographer.doCallbacks(Choreographer.java:796)
        at android.view.Choreographer.doFrame(Choreographer.java:731)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

问题原因及修复方案

原因分析

  1. LineDataSet初始化错误:初始化时传入null而非空列表,MPAndroidChart内部处理空数据集时可能出现计算异常,导致数组大小为负。
  2. 第一次传感器事件的逻辑错误:初始timestamp为0时,第一次执行累计值计算会得到异常大的值,后续Entry的X轴值可能导致范围计算出错;同时原代码添加数据点后才更新累计值,逻辑顺序颠倒。
  3. Entry的X轴值无序:如果X轴值出现非递增情况,MPAndroidChart渲染时计算显示范围会触发NegativeArraySizeException。

修复步骤

  1. 初始化LineDataSet时传入空MutableList:将LineDataSet(null, "X")改为LineDataSet(mutableListOf(), "X"),确保数据集初始状态合法。
  2. 调整传感器事件处理逻辑:
    • 第一次事件仅记录timestamp,不添加数据点;
    • 后续事件先计算时间间隔dt,更新累计值lastX/Y/Z,再基于累计值创建Entry添加到数据集;
    • 使用chart.data.notifyDataChanged()和chart.notifyDataSetChanged()正确通知图表更新。
  3. 统一时间戳类型:将timestamp改为Long类型,避免Double类型的精度问题。

内容的提问来源于stack exchange,提问作者이건웅

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:31:13