MPAndroidChartでリアルタイムプロットサンプル（kotlin）

MPAndroidChartを使ったリアルタイム更新グラフのサンプルを作成した。
公式にサンプル（https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartExample/src/main/java/com/xxmassdeveloper/mpchartexample/RealtimeLineChartActivity.java）
にあるが、Javaで書かれているため、ここでは公式を参考にKotlinで書いていく。

まず、build.gradleにviewBindingの設定とMPAndroidChartのインポート設定を行う。


```xml:app/build.gradle
...
android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

dependencies {
    ...
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}
...
```

また、レイアウトは以下のように作成する。

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <com.github.mikephil.charting.charts.LineChart
        android:id="@+id/lineChartExample"
        android:layout_width="333dp"
        android:layout_height="488dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/monitor_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="feedMultiple"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/lineChartExample" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

そこで、MainActivity.ktを以下のように記述。

```kotlin:MainActivity.kt

class MainActivity : AppCompatActivity() {

    private var chart: LineChart? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        chart = binding.lineChartExample.apply {
            isDragEnabled = false
            setTouchEnabled(false)
            setScaleEnabled(true)
            setDrawGridBackground(false)
            setPinchZoom(false)
//            setBackgroundColor(Color.LTGRAY)

            data = LineData().apply {
//                setValueTextColor(Color.WHITE)
                addDataSet(createSet("x", Color.RED))
                addDataSet(createSet("y", Color.GREEN))
                addDataSet(createSet("z", Color.BLUE))
            }

            description.apply {
                isEnabled = false
            }

            legend.apply {
//                textColor = Color.WHITE
                form = LegendForm.LINE
            }

            xAxis.apply {
//                textColor = Color.WHITE
//                isEnabled = false
                setAvoidFirstLastClipping(true)
                setDrawGridLines(true)
            }

            axisLeft.apply {
//                textColor = Color.WHITE
                axisMaximum = 35.0f
                axisMinimum = -5.0f
                setDrawGridLines(true)
            }

            axisRight.apply {
                isEnabled = false
            }


        }
    }

    private fun addEntry() {
        chart?.apply{
            data.apply {
                val set1 = getDataSetByIndex(0)
                val set2 = getDataSetByIndex(1)
                val set3 = getDataSetByIndex(2)
                addEntry(Entry(set1.entryCount.toFloat(), (Math.random() * 10).toFloat() + 0f), 0)
                addEntry(Entry(set2.entryCount.toFloat(), (Math.random() * 10).toFloat() + 10f), 1)
                addEntry(Entry(set3.entryCount.toFloat(), (Math.random() * 10).toFloat() + 20f), 2)
                notifyDataChanged()
            }
            notifyDataSetChanged()
            setVisibleXRangeMaximum(200.0f)
            moveViewToX(data.entryCount.toFloat())
        }
    }

    private fun createSet(label: String, c: Int): LineDataSet {
        return LineDataSet(null, label).apply {
            axisDependency = AxisDependency.LEFT
            color = c
            lineWidth = 1.0f
            setDrawCircles(false)
            setDrawValues(false)
        }
    }

    private var thread: Thread? = null

    fun feedMultiple(view: View) {
        if (thread != null) thread!!.interrupt()
        val runnable = Runnable {
            addEntry()
        }
        thread = Thread(Runnable {
            for (i in 0..999) {
                runOnUiThread(runnable)
                try {
                    Thread.sleep(25)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
            }
        })
        thread!!.start()
    }

    override fun onPause() {
        super.onPause()
        if (thread != null) {
            thread!!.interrupt()
        }
    }
}
```