因此,我希望每秒调用一次函数“ start()”,直到按下按钮为止。
该函数读取JSON文件并在GraphView
库的帮助下通知绘图仪打印折线图。
我尝试了此操作,但应用程序不断崩溃:
private val timer = Timer("schedule", true)
timer.scheduleAtFixedRate(1000,1000)
{
start()
}
Json Parser:连接到URL,提取json并从中提取数据。
object JsonParser {
var blueConeArray = arrayListOf<Cone>()
var yellowConeArray = arrayListOf<Cone>()
//Parse Json File extract Data and store them in DataWarehouse
fun parse(url: String) {
getRequest(url, success = { response ->
//create Parser
val parser = Parser()
val stringBuilder = StringBuilder(response)
//Read Json File + get Data
val jsonObject : JsonObject = parser.parse(stringBuilder) as JsonObject
//Get Cones from JsonObject
val blueCoordinates : JsonArray<JsonObject>? = jsonObject.array("BlueCoordinates")
val yellowCoordinates : JsonArray<JsonObject>? = jsonObject.array("YellowCoordinates")
//Store Blue Cones
for(coordinate in blueCoordinates!!)
{
var x_blue = coordinate.double("x")
var y_blue = coordinate.double("y")
var blueCone = BlueCone(x_blue!!, y_blue!!)
blueConeArray.add(blueCone)
}
//Store Yellow Cones
for(coordinate in yellowCoordinates!!)
{
var x_yellow = coordinate.double("x")
var y_yellow = coordinate.double("y")
var yellowCone = YellowCone(x_yellow!!, y_yellow!!)
yellowConeArray.add(yellowCone)
}
//Store everything in Data Warehouse
DataWarehouse.setValues(newEngineTemp = jsonObject.string("engineTemp"),
newSpeed = jsonObject.string("speed"),
newBlueCones = blueConeArray,
newYellowCones = yellowConeArray)
blueConeArray.clear()
yellowConeArray.clear()
}, failure = { error ->
println(error)
})
}
//connect to URL pull Json File
private fun getRequest(url: String, success: (String) -> Unit, failure: (FuelError) -> Unit) {
Fuel.get(url).responseString { request, response, result ->
val (data, error) = result
if (error != null) {
Log.v("Error", error.toString())
failure(error)
} else {
val onSuccess = data ?: return@responseString
success(onSuccess)
}
}
}
}
DataWarehouse:存储来自Json Parser的数据并通知观察者
object DataWarehouse : Subject {
//List of Observers
private val MAXOBSERVER = 100
private var amountOfObservers = 0
private var observerList = arrayListOf<Observer>()
//Data from car
private var engineTemp: String? = ""
private var speed: String? = ""
private lateinit var blueCones : ArrayList<Cone>
private lateinit var yellowCones : ArrayList<Cone>
//register Observers + save them in Array
override fun registerObserver(DataObserver: Observer) {
if (amountOfObservers < MAXOBSERVER) {
observerList.add(DataObserver)
amountOfObservers++
}
}
//notify Observer from Array, that needs the new Value
override fun notifyObservers() {
for (observer in observerList) {
observer.update()
}
}
//set values from parsed Jason File
fun setValues(newEngineTemp: String?, newSpeed: String? ,newBlueCones: ArrayList<Cone>, newYellowCones: ArrayList<Cone>) {
//set new Values
engineTemp = newEngineTemp
speed = newSpeed
blueCones = newBlueCones
yellowCones = newYellowCones
//notify all Observers
notifyObservers()
}
//Return values to Observers
fun getEngineTemp(): String? {
return engineTemp
}
fun getSpeed(): String? {
return speed
}
fun getBlueCones(): ArrayList<Cone> {
return blueCones
}
fun getYellowCones(): ArrayList<Cone> {
return yellowCones
}
}
GraphView绘图仪:首先在(0/0)创建数据点,以便“ resetData()”起作用。
class Plotter(graphView: GraphView) : Observer {
private var graphView = graphView
private lateinit var sortedBlueCones: MutableList<Cone>
private lateinit var sortedYellowCones: MutableList<Cone>
private var blueConeArrayList = ArrayList<DataPoint>()
private var yellowConeArrayList = ArrayList<DataPoint>()
private var blueLines = LineGraphSeries<DataPoint>()
private var yellowLines = LineGraphSeries<DataPoint>()
private var blueIterator = 0
private var yellowIterator = 0
private var firstDraw = true
init {
//First Values so resetData works
yellowLines.appendData((DataPoint(0.toDouble(), 0.toDouble())), true, 1000)
blueLines.appendData((DataPoint(0.toDouble(), 0.toDouble())), true, 1000)
register()
}
//Register at Data Warehouse
override fun register() {
DataWarehouse.registerObserver(this)
}
//Get new Cones from Data Warehouse and sort them by X Values
override fun update() {
sortedBlueCones = DataWarehouse.getBlueCones().sortedWith(compareBy({ it.xCoordinate })) as MutableList<Cone>
sortedYellowCones = DataWarehouse.getYellowCones().sortedWith(compareBy({ it.xCoordinate })) as MutableList<Cone>
draw()
}
//Draw Line Graph and Point Graph
private fun draw() {
//Blue Cones
for (i in sortedBlueCones) {
var x: Double = sortedBlueCones.get(blueIterator).xCoordinate
var y: Double = sortedBlueCones.get(blueIterator).yCoordinate
var dataPoint = DataPoint(x, y)
blueConeArrayList.add(dataPoint)
val blueConeArray = arrayOfNulls<DataPoint>(blueConeArrayList.size)
blueConeArrayList.toArray(blueConeArray)
blueLines.resetData(blueConeArray)
blueIterator++
}
//Yellow Cones
for (i in sortedYellowCones) {
var x: Double = sortedYellowCones.get(yellowIterator).xCoordinate
var y: Double = sortedYellowCones.get(yellowIterator).yCoordinate
var dataPoint = DataPoint(x, y)
yellowConeArrayList.add(dataPoint)
val yellowConeArray = arrayOfNulls<DataPoint>(yellowConeArrayList.size)
yellowConeArrayList.toArray(yellowConeArray)
yellowLines.resetData(yellowConeArray)
yellowIterator++
}
//Set Values of Lines
blueLines.setColor(Color.BLUE)
blueLines.setDrawDataPoints(true)
blueLines.setDataPointsRadius(10.toFloat())
yellowLines.setColor(Color.YELLOW)
yellowLines.setDrawDataPoints(true)
yellowLines.setDataPointsRadius(10.toFloat())
//Draw
graphView.addSeries(blueLines)
graphView.addSeries(yellowLines)
blueIterator = 0
yellowIterator = 0
}
}
错误堆栈:它看起来像是graphView的问题,但是当我使用Button手动触发该函数时,它工作得很好。每当我在计时器中包装“ start()”或“ readJson()”时,应用程序就会崩溃。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tobias.infinity_racing_driverless, PID: 16341
java.lang.IllegalArgumentException: The order of the values is not correct. X-Values have to be ordered ASC. First the lowest x value and at least the highest x value.
at com.jjoe64.graphview.series.BaseSeries.checkValueOrder(BaseSeries.java:532)
at com.jjoe64.graphview.series.BaseSeries.resetData(BaseSeries.java:412)
at com.example.tobias.infinity_racing_driverless.Plotter.draw(Plotter.kt:69)
at com.example.tobias.infinity_racing_driverless.Plotter.update(Plotter.kt:52)
at com.example.tobias.infinity_racing_driverless.DataWarehouse.notifyObservers(DataWarehouse.kt:32)
at com.example.tobias.infinity_racing_driverless.DataWarehouse.setValues(DataWarehouse.kt:46)
at com.example.tobias.infinity_racing_driverless.JsonParser$parse$1.invoke(JsonParser.kt:55)
at com.example.tobias.infinity_racing_driverless.JsonParser$parse$1.invoke(JsonParser.kt:14)
at com.example.tobias.infinity_racing_driverless.JsonParser$getRequest$1.invoke(JsonParser.kt:78)
at com.example.tobias.infinity_racing_driverless.JsonParser$getRequest$1.invoke(JsonParser.kt:14)
at com.github.kittinunf.fuel.core.DeserializableKt$response$1.invoke(Deserializable.kt:105)
at com.github.kittinunf.fuel.core.DeserializableKt$response$1.invoke(Unknown Source:4)
at com.github.kittinunf.fuel.core.DeserializableKt$response$asyncRequest$1$1.invoke(Deserializable.kt:192)
at com.github.kittinunf.fuel.core.DeserializableKt$response$asyncRequest$1$1.invoke(Unknown Source:0)
at com.github.kittinunf.fuel.core.RequestExecutionOptionsKt$sam$java_lang_Runnable$0.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
答案 0 :(得分:0)
1)计时器在工作线程上调度任务。我猜是因为 start()函数正在更新工作线程上的GraphView(UI)而发生错误。因此,请尝试将start函数包装在UI / Main处理程序中,如下所示。
private val timer = Timer("schedule", true)
timer.scheduleAtFixedRate(1000,1000)
{
Handler(Looper.getMainLooper()).post {
start()
}
}
2)但是,如果再次花时间读取json文件,最好只将Grapview更新代码包装在Handler中,而不是整个start()函数。因此, start()函数中的代码必须像下面的
fun start()
{
// your code to read the json file
// wrap the notify grapview plotter inside Handler
Handler(Looper.getMainLooper()).post {
// code to notify Grapview plotter
}
}