Skip to content

Realm.io database integration

Philipp Jahoda edited this page Jan 3, 2018 · 12 revisions

Since v2.2.0 MPAndroidChart supports plotting data coming directly from the Realm.io mobile database.

Since v3.0.0, the Realm.io related code has been moved to a separate repository MPAndroidChart-Realm.

Tutorial

This short tutorial will show how to directly plot data stored in realm.io mobile database with MPAndroidChart-Realm library. For general documentation regarding realm.io, how to use the database, how to read or write objects, please visit their official documentation.

In order to plot data with Realm, you need to add the following dependencies to your project:

The gradle dependency to Realm.io is only required if you want to use the realm specific features of this library. If only basic chart features are used that do not require interaction with realm database, the dependency is not needed.

The actual tutorial scenario looks as follows:

Data Class

We have a data class Score, extending RealmObject (required) which stores the totalscore of an imaginary game as well as a scoreNr that will represent a simple incrementing counter and a playername. We want to plot all data stored in Realm represented by a Score object.

public class Score extends RealmObject {

    private float totalScore;

    private float scoreNr;

    private String playerName;

    public Score() { } // no arguments constructor required for realm

    public Score(float totalScore, float scoreNr, String playerName) {
        this.scoreNr = scoreNr;
        this.playerName = playerName;
        this.totalScore = totalScore;
    }

    // all getters and setters (required for realm) ...
}

Make sure your data class provides a no arguments constructor (in addition to any other constructors you might have) as well as all required getter and setter methods. This is required for Realm to work.

Realm Instance & data

In order to be able to access the data stored in realm database, we need a realm database instance:

// get realm instance
Realm realm = Realm.getDefaultInstance();

For detailed information on how to set up your realm instance (with RealmConfiguration), please have a look here. In this tutorial, we assume our realm database-data looks like this:

class playerName (x-value) totalScore (y-value) scoreNr (x-value)
Score Peter 100 0
Score Lisa 110 1
Score Dennis 130 2
Score Luke 70 3
Score Sarah 80 4

The code to store the previously mentioned Score objects in the local realm-database can for example look like this:

realm.beginTransaction();

Score score1 = new Score(100f, 0f, "Peter");
realm.copyToRealm(score1);
Score score2 = new Score(110f, 1f, "Lisa");
realm.copyToRealm(score2);
Score score3 = new Score(130f, 2f, "Dennis");
realm.copyToRealm(score3);
Score score4 = new Score(70f, 3f, "Luke");
realm.copyToRealm(score4);
Score score5 = new Score(80f, 4f, "Sarah");
realm.copyToRealm(score5);

realm.commitTransaction();

Plotting Realm data

Now, what we want to do is plot all data shown above in a BarChart directly from realm. The scoreNr will be used as an x-value. In order to do all that, we need our realm-object as well as a RealmResults List of our data object Score. As a first step, we need to query the realm data:

// get the data from realm (of course more complex queries are possible here)
RealmResults<Score> results = realm.where(Score.class).findAll();

For plotting the names of all players on the XAxis, we need to create an instance of IAxisValueFormatter :

  IAxisValueFormatter formatter = new IAxisValueFormatter () {
      @Override
      public String getFormattedValue(float value, AxisBase axis) {
          return results.get((int) value).getPlayerName();
      }

      @Override
      public int getDecimalDigits() { return 0; }
  };

What this formatter does is use the "playerName" of the queried data and plot it on the XAxis for a given value. In this case, the float value parameter provided by the formatter corresponds to the range of x-axis values the chart has (5 in that case, because minimum "scoreNr" is 0, and maximum is 5). As we do not plot any numbers on the XAxis, we can return 0 from the getDecimalDigits() method.

After the axis-formatter is set up, we need to setup our RealmBarDataSet. The constructor (one of the constructors) looks as follows:

public RealmBarDataSet(RealmResults<T> results, String xValuesField, String yValuesField) { ... }

As the parameter results we will provide our results list we just queried from realm. The String yValuesField will be the name of the member variable of the Score class that should represent the y-value plotted in the chart. In our case, we want to plot the totalscore, so we will provide "totalScore" as the parameter. For the xValuesField parameter we want to provide the name of the member variable that should be used as an x-value. In this case, we will provide "scoreNr" as a parameter. Please be aware that these parameters are case sensitive. The final DataSet should look like this:

RealmBarDataSet<Score> dataSet = new RealmBarDataSet<Score>(results, "scoreNr", "totalScore");
// apply additional styling...

After creating the DataSet, we need to add it to a BarData object. The class BarData a constructor that looks like this:

public BarData(List<IBarDataSet> dataSets) { ... }

All that has to be done now is to add the created RealmBarDataSet to the BarData object. The result should look something like this:

RealmBarDataSet<Score> dataSet = ...;

ArrayList<IBarDataSet> dataSetList = new ArrayList<IBarDataSet>();
dataSetList.add(dataSet); // add the dataset

// create a data object with the dataset list
BarData data = new BarData(dataSetList);
// additional data styling...

Last but not least, we add the BarData object to our BarChart and refresh it:

// set data
barChart.setData(data);
barChart.invalidate(); // refresh

The Result

The plotted result should look somewhat like this: alt tag

Of course chart appearance & data styling depends on your individual settings. All realm-created charts can be styled just the same way as charts fed with data from other data sources.

Potting data with all other chart types works quite similar. An exception are stacked-bars, which require a special object (RealmList) to represent the float[] array in which the individual stack-values are stored.

Troubleshooting

Common Exceptions & issues:

  • java.lang.IllegalArgumentException: Illegal Argument: Field not found: fieldname. In case your app is throwing this Exception it means that the fieldnames you provided as a parameter for your RealmDataSet object do not match the fieldnames in your data class. Also be aware that these parameters are case sensitive.

  • Your data does not show up. In case your data does not show up in the chart despite you setup everything correctly, it's often small details you have missed that cause this issue. Don't forget to call invalidate() on your chart object to refresh it after setting the data.

  • java.lang.IllegalStateException: Changing Realm data can only be done from inside a transaction. This Exception means that you tried to store data in realm.io database outside of a so called "transaction". You always need to call realm.beginTransaction() beforehand and realm.commitTransaction() after you store data in realm with methods like realm.copyToRealm(...).

  • java.lang.IllegalArgumentException: Illegal Argument: ColumnType invalid. This Exception means that the data type of a variable in your data class does not correspond with the from the library expected data type. Beware that x- and y-values need to be of type float.

  • java.lang.IllegalArgumentException: "Classname" is not part of the schema for this Realm. This Exception can be thrown for various reasons. Most often, it is related to changes to the data model where a class that is already stored in realm database was modified (in terms of it's member variables) and therefore causes problems when storing. This issue can also be related to corrupted cache, where the application is still using and old version of realm whilst a new version was added as a dependency. Cleaning the project & the gradle cache can help in that case.

If you are experiencing an issue not mentioned above or are still having problems, please refer to the help section of Realm mobile database.

Links

Clone this wiki locally