按下图形会导致应用程序崩溃
pressing the graph causes the application to crash
我有一个问题,如何在 phone 上打开应用程序并尝试按 MPAndroidChart 中的图表,它让我退出应用程序,我写道应用程序正在崩溃。
link 到我从中获取文档的页面 [此处][1]
我对图表有疑问。我的图表从 csv 文件中获取数据,并以小时、分钟和秒为单位给出时间。如何校准图形以使时间每 60 分钟而不是每 100 分钟显示一次
我的
主要活动
package com.example.aplikacjadlataty
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.Switch
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.animation.Easing
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.google.android.gms.ads.MobileAds
import kotlinx.android.synthetic.main.activity_main.*
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
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
val lineChart = findViewById<LineChart>(R.id.lineChart)
val vl = LineDataSet(newEntries.toList().take(4000), "cost")
vl.setDrawValues(false)
vl.setDrawFilled(true)
vl.lineWidth = 1.5f
vl.fillColor = R.color.gray
vl.fillAlpha = R.color.red
vl.setDrawCircles(false)
lineChart.data = LineData(vl)
lineChart.notifyDataSetChanged()
lineChart.animateX(1800, Easing.EaseInExpo)
lineChart.description.isEnabled = false
lineChart.isHighlightPerDragEnabled = false
lineChart.isScaleYEnabled = false
lineChart.axisRight.isEnabled = false
// lineChart.xAxis.valueFormatter = MyAxisFormatter()
// lineChart.xAxis.granularity = 60f
}
findViewById<Button>(R.id.button_loadCsv)?.setOnClickListener {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "text/*"
getContent.launch("text/*")
}
val button = findViewById<Button>(R.id.button_loadCsv)
val text = findViewById<TextView>(R.id.text)
val sw1 = findViewById<Switch>(R.id.switch1)
sw1?.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) screen.setBackgroundColor(Color.DKGRAY)
else screen.setBackgroundColor(Color.WHITE)
if (isChecked) layout.setBackgroundColor(Color.DKGRAY)
else layout.setBackgroundColor(Color.WHITE)
if (isChecked) AdsLayout.setBackgroundColor(Color.DKGRAY)
else AdsLayout.setBackgroundColor(Color.WHITE)
if (isChecked) text.text = "Set light mode"
else text.text = "Set dark mode"
if (isChecked) text.setTextColor(Color.WHITE)
else text.setTextColor(Color.BLACK)
if (isChecked) button.setTextColor(Color.WHITE)
else button.setTextColor(Color.BLACK)
if (isChecked) button.setBackgroundColor(Color.parseColor("#707070"))
else button.setBackgroundColor(Color.parseColor("#efefef"))
}
Log.d(
"MainActivity", "onCreate Called \n" +
" \n" +
" \n" +
" \n" +
" __ ___ ___ __ __ _____ ______ __ __ ____ __ _ __ ____ ___ __ __ \n" +
" / |/ / / | / //_/ / ___/ / ____/ / / / / / __ \ / / / | / / / _/ / | / //_/ \n" +
" / /|_/ / / /| | / ,< \__ \ / / / /_/ / / / / / __ / / / |/ / / / / /| | / ,< \n" +
" / / / / / ___ | / /| | ___/ / / /___ / __ / / /_/ / / /_/ / / /| / _/ / / ___ | / /| | \n" +
"/_/ /_/ /_/ |_|/_/ |_| /____/ \____/ /_/ /_/ \____/ \____/ /_/ |_/ /___/ /_/ |_|/_/ |_| \n" +
" \n" +
" \n" +
" "
)
MobileAds.initialize(this) {}
val markerView = CustomMarker(this@MainActivity, R.layout.marker_view)
lineChart.marker = markerView
}
@Throws(IOException::class)
fun readCSV(uri: Uri?): List<String> {
if (uri != null) {
val csvFile = contentResolver.openInputStream(uri)
val isr = InputStreamReader(csvFile)
return BufferedReader(isr).readLines()
}
return Collections.emptyList()
}
private fun toEntry(line: String): Entry {
val split = line.split(";")
return Entry(split[1].toFloat(), split[2].toFloat())
}
}
故障很明显。此处指定:
NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at com.example.aplikacjadlataty.CustomMarker.refreshContent(CustomMarker.kt:22)
因此转到 CustomMarker.kt 中的第 22 行并修复它。可能您没有对 tvPrice
的引用。你知道那个 ID 在哪里吗?
编辑
不看全文是做不到的。你有没有在你的项目中添加这个.XML
?
marker_view.xml
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:background="@drawable/oval_marker"
android:orientation="vertical">
<TextView
android:id="@+id/tvPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:text=""
android:textSize="10dp"
android:textColor="@android:color/white"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
在您的link、here
中有解释
编辑 2
按照我的代码。对我来说,我工作得很好:
低于MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.github.mikephil.charting.animation.Easing
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val lineChart = findViewById<LineChart>(R.id.lineChart)
//Part1
val entries = ArrayList<Entry>()
//Part2
entries.add(Entry(1f, 10f))
entries.add(Entry(2f, 2f))
entries.add(Entry(3f, 7f))
entries.add(Entry(4f, 20f))
entries.add(Entry(5f, 16f))
//Part3
val vl = LineDataSet(entries, "My Type")
//Part4
vl.setDrawValues(false)
vl.setDrawFilled(true)
vl.lineWidth = 3f
vl.fillColor = R.color.gray
vl.fillAlpha = R.color.red
//Part5
lineChart.xAxis.labelRotationAngle = 0f
//Part6
lineChart.data = LineData(vl)
//Part7
lineChart.axisRight.isEnabled = false
lineChart.xAxis.axisMaximum = 1 + 0.1f
//Part8
lineChart.setTouchEnabled(true)
lineChart.setPinchZoom(true)
//Part9
lineChart.description.text = "Days"
lineChart.setNoDataText("No forex yet!")
//Part10
lineChart.animateX(1800, Easing.EaseInExpo)
//Part11
val markerView = CustomMarker(this, R.layout.marker_view)
lineChart.marker = markerView
}
}
低于CustomMarker.kt
import android.content.Context
import android.widget.TextView
import com.github.mikephil.charting.components.MarkerView
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.highlight.Highlight
import com.github.mikephil.charting.utils.MPPointF
class CustomMarker(context: Context, layoutResource: Int): MarkerView(context, layoutResource) {
override fun refreshContent(entry: Entry?, highlight: Highlight?) {
val value = entry?.y?.toDouble() ?: 0.0
val tvPrice = findViewById<TextView>(R.id.tvPrice)
val resText: String = if(value.toString().length > 8){
"Val: " + value.toString().substring(0,7)
} else{
"Val: $value"
}
tvPrice.text = resText
super.refreshContent(entry, highlight)
}
override fun getOffsetForDrawingAtPoint(xpos: Float, ypos: Float): MPPointF {
return MPPointF(-width / 2f, -height - 10f)
}
}
这里 activity_main.xml
里面 res/layout
文件夹
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
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/lineChart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="10dp"
android:padding="9dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
这里 oval_marker.xml
里面 res/drawable
文件夹
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/gray" />
<stroke
android:width="1dp"
android:color="@color/colorWhite" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp" />
<corners
android:bottomLeftRadius="7dp"
android:bottomRightRadius="7dp"
android:topLeftRadius="7dp"
android:topRightRadius="7dp" />
</shape>
这里 gradient_bg.xml
里面 drawable
文件夹
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="@color/colorLight"
android:endColor="@color/colorDark"
android:angle="180"/>
</shape>
</item>
</selector>
这里 colors.xml
里面 res/values
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="green">#4CAF50</color>
<color name="red">#F44336</color>
<color name="colorDark">#666262</color>
<color name="colorLight">#F3D3D0</color>
<color name="gray">#4E4948</color>
<color name="colorWhite">#FFFFFF</color>
</resources>
我有一个问题,如何在 phone 上打开应用程序并尝试按 MPAndroidChart 中的图表,它让我退出应用程序,我写道应用程序正在崩溃。
link 到我从中获取文档的页面 [此处][1]
我对图表有疑问。我的图表从 csv 文件中获取数据,并以小时、分钟和秒为单位给出时间。如何校准图形以使时间每 60 分钟而不是每 100 分钟显示一次 我的
主要活动
package com.example.aplikacjadlataty
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.Switch
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.animation.Easing
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.google.android.gms.ads.MobileAds
import kotlinx.android.synthetic.main.activity_main.*
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
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
val lineChart = findViewById<LineChart>(R.id.lineChart)
val vl = LineDataSet(newEntries.toList().take(4000), "cost")
vl.setDrawValues(false)
vl.setDrawFilled(true)
vl.lineWidth = 1.5f
vl.fillColor = R.color.gray
vl.fillAlpha = R.color.red
vl.setDrawCircles(false)
lineChart.data = LineData(vl)
lineChart.notifyDataSetChanged()
lineChart.animateX(1800, Easing.EaseInExpo)
lineChart.description.isEnabled = false
lineChart.isHighlightPerDragEnabled = false
lineChart.isScaleYEnabled = false
lineChart.axisRight.isEnabled = false
// lineChart.xAxis.valueFormatter = MyAxisFormatter()
// lineChart.xAxis.granularity = 60f
}
findViewById<Button>(R.id.button_loadCsv)?.setOnClickListener {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "text/*"
getContent.launch("text/*")
}
val button = findViewById<Button>(R.id.button_loadCsv)
val text = findViewById<TextView>(R.id.text)
val sw1 = findViewById<Switch>(R.id.switch1)
sw1?.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) screen.setBackgroundColor(Color.DKGRAY)
else screen.setBackgroundColor(Color.WHITE)
if (isChecked) layout.setBackgroundColor(Color.DKGRAY)
else layout.setBackgroundColor(Color.WHITE)
if (isChecked) AdsLayout.setBackgroundColor(Color.DKGRAY)
else AdsLayout.setBackgroundColor(Color.WHITE)
if (isChecked) text.text = "Set light mode"
else text.text = "Set dark mode"
if (isChecked) text.setTextColor(Color.WHITE)
else text.setTextColor(Color.BLACK)
if (isChecked) button.setTextColor(Color.WHITE)
else button.setTextColor(Color.BLACK)
if (isChecked) button.setBackgroundColor(Color.parseColor("#707070"))
else button.setBackgroundColor(Color.parseColor("#efefef"))
}
Log.d(
"MainActivity", "onCreate Called \n" +
" \n" +
" \n" +
" \n" +
" __ ___ ___ __ __ _____ ______ __ __ ____ __ _ __ ____ ___ __ __ \n" +
" / |/ / / | / //_/ / ___/ / ____/ / / / / / __ \ / / / | / / / _/ / | / //_/ \n" +
" / /|_/ / / /| | / ,< \__ \ / / / /_/ / / / / / __ / / / |/ / / / / /| | / ,< \n" +
" / / / / / ___ | / /| | ___/ / / /___ / __ / / /_/ / / /_/ / / /| / _/ / / ___ | / /| | \n" +
"/_/ /_/ /_/ |_|/_/ |_| /____/ \____/ /_/ /_/ \____/ \____/ /_/ |_/ /___/ /_/ |_|/_/ |_| \n" +
" \n" +
" \n" +
" "
)
MobileAds.initialize(this) {}
val markerView = CustomMarker(this@MainActivity, R.layout.marker_view)
lineChart.marker = markerView
}
@Throws(IOException::class)
fun readCSV(uri: Uri?): List<String> {
if (uri != null) {
val csvFile = contentResolver.openInputStream(uri)
val isr = InputStreamReader(csvFile)
return BufferedReader(isr).readLines()
}
return Collections.emptyList()
}
private fun toEntry(line: String): Entry {
val split = line.split(";")
return Entry(split[1].toFloat(), split[2].toFloat())
}
}
故障很明显。此处指定:
NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at com.example.aplikacjadlataty.CustomMarker.refreshContent(CustomMarker.kt:22)
因此转到 CustomMarker.kt 中的第 22 行并修复它。可能您没有对 tvPrice
的引用。你知道那个 ID 在哪里吗?
编辑
不看全文是做不到的。你有没有在你的项目中添加这个.XML
?
marker_view.xml
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:background="@drawable/oval_marker"
android:orientation="vertical">
<TextView
android:id="@+id/tvPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:text=""
android:textSize="10dp"
android:textColor="@android:color/white"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
在您的link、here
中有解释 编辑 2 按照我的代码。对我来说,我工作得很好:低于MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.github.mikephil.charting.animation.Easing
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val lineChart = findViewById<LineChart>(R.id.lineChart)
//Part1
val entries = ArrayList<Entry>()
//Part2
entries.add(Entry(1f, 10f))
entries.add(Entry(2f, 2f))
entries.add(Entry(3f, 7f))
entries.add(Entry(4f, 20f))
entries.add(Entry(5f, 16f))
//Part3
val vl = LineDataSet(entries, "My Type")
//Part4
vl.setDrawValues(false)
vl.setDrawFilled(true)
vl.lineWidth = 3f
vl.fillColor = R.color.gray
vl.fillAlpha = R.color.red
//Part5
lineChart.xAxis.labelRotationAngle = 0f
//Part6
lineChart.data = LineData(vl)
//Part7
lineChart.axisRight.isEnabled = false
lineChart.xAxis.axisMaximum = 1 + 0.1f
//Part8
lineChart.setTouchEnabled(true)
lineChart.setPinchZoom(true)
//Part9
lineChart.description.text = "Days"
lineChart.setNoDataText("No forex yet!")
//Part10
lineChart.animateX(1800, Easing.EaseInExpo)
//Part11
val markerView = CustomMarker(this, R.layout.marker_view)
lineChart.marker = markerView
}
}
低于CustomMarker.kt
import android.content.Context
import android.widget.TextView
import com.github.mikephil.charting.components.MarkerView
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.highlight.Highlight
import com.github.mikephil.charting.utils.MPPointF
class CustomMarker(context: Context, layoutResource: Int): MarkerView(context, layoutResource) {
override fun refreshContent(entry: Entry?, highlight: Highlight?) {
val value = entry?.y?.toDouble() ?: 0.0
val tvPrice = findViewById<TextView>(R.id.tvPrice)
val resText: String = if(value.toString().length > 8){
"Val: " + value.toString().substring(0,7)
} else{
"Val: $value"
}
tvPrice.text = resText
super.refreshContent(entry, highlight)
}
override fun getOffsetForDrawingAtPoint(xpos: Float, ypos: Float): MPPointF {
return MPPointF(-width / 2f, -height - 10f)
}
}
这里 activity_main.xml
里面 res/layout
文件夹
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
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/lineChart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="10dp"
android:padding="9dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
这里 oval_marker.xml
里面 res/drawable
文件夹
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/gray" />
<stroke
android:width="1dp"
android:color="@color/colorWhite" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp" />
<corners
android:bottomLeftRadius="7dp"
android:bottomRightRadius="7dp"
android:topLeftRadius="7dp"
android:topRightRadius="7dp" />
</shape>
这里 gradient_bg.xml
里面 drawable
文件夹
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="@color/colorLight"
android:endColor="@color/colorDark"
android:angle="180"/>
</shape>
</item>
</selector>
这里 colors.xml
里面 res/values
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="green">#4CAF50</color>
<color name="red">#F44336</color>
<color name="colorDark">#666262</color>
<color name="colorLight">#F3D3D0</color>
<color name="gray">#4E4948</color>
<color name="colorWhite">#FFFFFF</color>
</resources>