javaandroidillegalargumentexceptionandroid-graphview

Why does java.lang.IllegalArgumentException error appear when order of values is correct?


I am a student currently in my second year of A-level computer science. I have coursework project and I decided to make a fitness app using Android Studio and I have an error which I can't solve and don't understand why it is happening. The error is caused by the code in (activity). I have put a comment on that line according to Logcat (this is the code dataseries.resetData(grabData());.) It located in the public void insertData() {.

The error I get is 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. The full details of the error can be seen below.

I used a tutorial on YouTube to help me to make a graph view (as I want to make a graph that has user inputs on the y-axis and date x-axis). I have done everything it says in the video as well. This is the video I used.

I had no idea of how to fix this problem so the only thing I've done so far is to redo the code just to make sure I haven't done anything wrong. However, I still get the error. I have tried contacting the person who made the video but he hasn't responded and probably won't because he hasn't been recently uploading on his social media.

This is the code for the graph and user input (activity wTrackingTestingActivity):

package com.example.fitmania;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.jjoe64.graphview.DefaultLabelFormatter;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;

import java.text.SimpleDateFormat;
import java.util.Date;

public class wTrackingTestingActivity extends AppCompatActivity {

    Button insertButton;
    EditText inputTextY;
    GraphView graphView;
    DatabaseHandler dbh;
    SQLiteDatabase sqLiteDatabase;
    LineGraphSeries<DataPoint> dataseries = new LineGraphSeries<>(new DataPoint[0]);

    @SuppressLint("SimpleDateFormat")
    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_w_tracking_testing);

        insertButton = (Button) findViewById(R.id.insertButton);
        inputTextY = (EditText) findViewById(R.id.inputTextY);
        graphView = (GraphView) findViewById(R.id.graph);

        dbh = new DatabaseHandler(this);
        sqLiteDatabase = dbh.getWritableDatabase();

        graphView.addSeries(dataseries);

        insertData();
    }


    public void insertData() {
        insertButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //set data and add to the database
                    //x value == date
                long xValue = new Date().getTime();
                    //y value == user input
                int yValue = Integer.parseInt(String.valueOf(inputTextY.getText()));

                dbh.insertToData(xValue, yValue);

                //grab the data and add to graph
                dataseries.resetData(grabData());    //THIS LINE IS CAUSING THE ERROR ACCORDING TO THE LOGCAT

                graphView.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter(){
                    @Override
                    public String formatLabel(double value, boolean isValueX) {
                        if (isValueX){
                            return sdf.format(new Date((long)value));
                        } else {
                            return super.formatLabel(value, isValueX);
                        }
                    }
                });





            }
        });
    }


    private DataPoint[] grabData() {

        String [] column = {"xValue", "yValue"};
        //circle through database to grab data and close query after using it
        @SuppressLint("Recycle") Cursor cursor = sqLiteDatabase.query("Table1", column, null, null, null, null, null);

        DataPoint[] dataPoints = new DataPoint[cursor.getCount()];

        //for loop to loop through data to get each data point
        for (int i=0; i < cursor.getCount(); i++) {
            cursor.moveToNext();
            dataPoints[i] = new DataPoint(cursor.getLong(0), cursor.getInt(1));
        }
        return dataPoints;
    }



}

This is code for the database (Java class DatabaseHandler):

package com.example.fitmania;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

public class DatabaseHandler extends SQLiteOpenHelper {


    public DatabaseHandler(Context context) {
        super(context, "Database1", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //create table
        String CreateTable = "create table Table1 (xValue INTEGER,yValue INTEGER)";
        db.execSQL(CreateTable);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }


    public void insertToData(long ValX, int ValY) {

        SQLiteDatabase database = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();

        contentValues.put("xValue",ValX);
        contentValues.put("yValue",ValY);

        database.insert("Table1", null, contentValues);

    }



}

This is the error I am getting:

    2020-03-22 17:40:10.828 27782-27782/com.example.fitmania E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.fitmania, PID: 27782
    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.fitmania.wTrackingTestingActivity$1.onClick(wTrackingTestingActivity.java:66)
        at android.view.View.performClick(View.java:6897)
        at android.widget.TextView.performClick(TextView.java:12693)
        at android.view.View$PerformClick.run(View.java:26101)
        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:6944)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

This the XML file for graph and user inputs (activity wTrackingTestingActivity, XML activity_w_tracking_testing):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".wTrackingTestingActivity">

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/inputTextY"
        app:layout_constraintBottom_toTopOf="@+id/graph"
        android:hint="Enter your weight"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.522"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/insertButton"
        android:layout_alignParentEnd="true"
        android:text="Button"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        app:layout_constraintBottom_toTopOf="@+id/graph"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_toEndOf="@+id/inputTextY"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_toRightOf="@+id/inputTextY"
        android:layout_alignParentRight="true" />

    <com.jjoe64.graphview.GraphView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/graph"
        android:layout_marginStart="16dp"
        android:layout_below="@+id/inputTextY"
        app:layout_constraintTop_toBottomOf="@+id/inputTextY"
        app:layout_constraintVertical_bias="1.0"
        android:layout_marginLeft="16dp" />

</RelativeLayout>

Solution

  • The error message says

    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.

    This means you have to make sure that the values are in the correct order before passing them to LineGraphSeries<DataPoint>.resetData().

    In grabData(), you retrieve the values by means of

    Cursor cursor = sqLiteDatabase.query("Table1", column, null, null, null, null, null);
    

    Looking up the documentation for this method shows that if you pass null as last parameter, the result set may well be unordered (with respect to the xValue column).

    To get an ordered result set, you have to pass in part of the ORDER BY clause.

    The whole statement would be

    SELECT xValue, yValue FROM Table1 ORDER BY xValue
    

    You need to pass just "xValue" as last parameter:

    Cursor cursor = sqLiteDatabase.query("Table1", column, null, null, null, null, "xValue");