In questo breve tutorial vedremo come realizzare un grafico in Android Studio per i nostri dispositivi Ltouch, utilizzando la libreria esterna jjoe64/GraphView in pochi e semplici passaggi. L’esempio da noi proposto andrà a realizzare un grafico avente come asse delle ascisse il tempo trascorso e come asse delle ordinate l’andamento della temperatura. Quest’ultima data da una sonda di temperatura PT100 collegata al dispositivo tramite ingresso analogico ( nulla vieta che la comunicazione possa avvenire in Modbus RTU ). I dati vengono letti e scritti su di una tabella ( temperature_table ) all’interno di un database locale ( DB_CHART.db ) ma in questa guida ci occuperemo solo della lettura quindi consiglio la visione del seguente articolo .
Nel caso in cui un passaggio dovesse essere poco chiaro oppure abbiate bisogno di maggiori informazioni ( per quanto riguarda la realizzazione del grafico ) tutto il materiale da cui attingere è reperibile al seguente indirizzo.
Detto ciò, il primo passaggio prevede di implementare la dipendenza nel build.gradle tramite il seguente comando:

[sourcecode language="java"]
implementation 'com.jjoe64:graphview:4.2.2'
[/sourcecode]

Nel secondo passaggio invece si dovrà aprire il file xml dell’attività ( Es. layout/activity_main.xml ) e aggiungere il tag per creare il grafico vero e proprio ( disporlo all’interno a piacimento ):

[sourcecode language="xml"]

[/sourcecode]

Nel terzo passaggio:
-Per prima cosa inizializziamo le variabli…

[sourcecode language="java"]
LineGraphSeries dataseries = new LineGraphSeries<>(new DataPoint[0]);
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyynHH:mm:ss");
//Nell'onCreate()
mioGrafico = (GraphView) findViewById(R.id.TempChart);
[/sourcecode]

-Dopo di che dando per scontato che il database si già popolato, utilizzo il metodo getAllData() contenuto nella classe DatabaseHelper in questo modo:

[sourcecode language="java"]
//Ottengo i vari DataPoint ( valoreX, valoreY ) da applicare in seguito al grafico
dataseries.resetData(mioDBHelper.getAllData());
[/sourcecode]

Il metodo getAllData() non fa altro che un SELECT di tutti i dati all’interno della tabella ( temperature_table ) e crea un vettore DataPoint ( che è quello che poi restituisce ). Quest’ultimo contiene i vari punti del grafico ovvero l’associazione ( asseX / asseY ) dove per asseX si intende prendere il valore della riga la cui corrispondente colonna è rappresentata da Time ( in Unix timestamp ) mentre per asseY si intende prendere il valore della riga per cui la corrispondente colonna è rappresentata da Temperature:

[sourcecode language="java"]
/**
<%%KEEPWHITESPACE%%> * Metodo per ottenere tutti i dati presenti all'interno della tabella temperature_table
<%%KEEPWHITESPACE%%> * ( anche se alla fine tengo conto solo delle colonne Time e Temperature
<%%KEEPWHITESPACE%%> * @return : DataPoint[]
<%%KEEPWHITESPACE%%> */
public DataPoint[] getAllData(){
<%%KEEPWHITESPACE%%>    //Ottengo il DB in modalità lettura
<%%KEEPWHITESPACE%%>    SQLiteDatabase mioDB = this.getReadableDatabase();
<%%KEEPWHITESPACE%%>    //Creo un oggetto Cursor per selezionare tutti i dati all'interno della tabella
<%%KEEPWHITESPACE%%>    Cursor mioCursor = mioDB.rawQuery("SELECT * FROM "+TABLE_name,null);
<%%KEEPWHITESPACE%%>    //Istanzio DataPoint di dimensione pari a mioCursore.getCount() ( ovvero pari al numero di
<%%KEEPWHITESPACE%%>    // righe )
<%%KEEPWHITESPACE%%>    DataPoint[] mieiDataPoint = new DataPoint[mioCursor.getCount()];
<%%KEEPWHITESPACE%%>    //Con questo ciclo creo i vari datapoint (x,y) e prendo min e max di entrambi gli assi
<%%KEEPWHITESPACE%%>    for(int i = 0; i &lt; mioCursor.getCount(); i++){
<%%KEEPWHITESPACE%%>        mioCursor.moveToNext();
<%%KEEPWHITESPACE%%>        if (i == 0){
<%%KEEPWHITESPACE%%>            MinX = mioCursor.getInt(mioCursor.getColumnIndex("Time"));
<%%KEEPWHITESPACE%%>            MinY = mioCursor.getDouble(mioCursor.getColumnIndex("Temperature"));
<%%KEEPWHITESPACE%%>        }
<%%KEEPWHITESPACE%%>        if(i == (mioCursor.getCount()-1)){
<%%KEEPWHITESPACE%%>            MaxX = mioCursor.getInt(mioCursor.getColumnIndex("Time"));
<%%KEEPWHITESPACE%%>            MaxY = mioCursor.getDouble(mioCursor.getColumnIndex("Temperature"));
<%%KEEPWHITESPACE%%>        }
<%%KEEPWHITESPACE%%>        mieiDataPoint[i] = new DataPoint(mioCursor.getInt(mioCursor.getColumnIndex("Time")),mioCursor.getDouble(mioCursor.getColumnIndex("Temperature")));
<%%KEEPWHITESPACE%%>    }
<%%KEEPWHITESPACE%%>    //Chiudo il db ( aperto in modalità lettura )
<%%KEEPWHITESPACE%%>    mioDB.close();
<%%KEEPWHITESPACE%%>    return mieiDataPoint;
}
[/sourcecode]

A questo punto non rimane altro da fare che il seguente comando per caricare DataPoint[] all’interno del grafico

[sourcecode language="java"]
mioGrafico.addSeries(dataseries);
[/sourcecode]

Nel caso in cui si voglia ottenere un qualcosa di più elaborato propongo di seguito un’altro esempio

[sourcecode language="java"]
//Imposto colore della linea del grafico
dataseries.setColor(Color.GREEN);
//Imposto se mettere o meno i punti ( in questo caso si )
dataseries.setDrawDataPoints(true);
//Imposto il raggio dei punti
dataseries.setDataPointsRadius(5);
//Imposto la grossezza della linea
dataseries.setThickness(3);
/*
<%%KEEPWHITESPACE%%>   Per settare maualmente l'asse y...
<%%KEEPWHITESPACE%%>   mioGrafico.getViewport().setYAxisBoundsManual(true);
<%%KEEPWHITESPACE%%>   mioGrafico.getViewport().setMinY(mioDBHelper.getMinY());
<%%KEEPWHITESPACE%%>   mioGrafico.getViewport().setMaxY(mioDBHelper.getMaxY())
*/
//Setto manualmente l'asse x
mioGrafico.getViewport().setXAxisBoundsManual(true);
//Specifico valore minimo asse x
mioGrafico.getViewport().setMinX(mioDBHelper.getMinX());
//Specifico valore massimo asse x
mioGrafico.getViewport().setMaxX(mioDBHelper.getMaxX());
//Do la possibilità di fare lo zoom e lo scroll
mioGrafico.getViewport().setScalable(true);
mioGrafico.getGridLabelRenderer().setHumanRounding(false); //In quanto uso data e ora come asse delle x
//Aggiungo al grafico i DataPoint
mioGrafico.addSeries(dataseries);
[/sourcecode]

Il risultato ottenuto dovrebbe essere simile a quello in figura:

Come potrete notare manca solo un’ultimo passaggio ovvero la conversione Unix timestamp in data e ora comprensibili. La libreria ci viene in contro fornendoci gli strumenti per cambiare manualmente le label degli assi quindi basterà utilizzare quelli per raggiungere il nostro scopo.

[sourcecode language="java"]
mioGrafico.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter(){
<%%KEEPWHITESPACE%%>    @Override
<%%KEEPWHITESPACE%%>    public String formatLabel(double value, boolean isValueX) {
<%%KEEPWHITESPACE%%>        if(isValueX){
<%%KEEPWHITESPACE%%>            //Come mostrare i valori dell'asse x
<%%KEEPWHITESPACE%%>            //Ora legale europa centrale
<%%KEEPWHITESPACE%%>            sdf.setTimeZone(TimeZone.getTimeZone("GMT+2"));
<%%KEEPWHITESPACE%%>            return sdf.format(new Date((long) value * 1000L));
<%%KEEPWHITESPACE%%>        }else{
<%%KEEPWHITESPACE%%>            //Come mostrare i valori dell'asse y
<%%KEEPWHITESPACE%%>            return super.formatLabel(value,isValueX);
<%%KEEPWHITESPACE%%>        }
<%%KEEPWHITESPACE%%>    }
});
[/sourcecode]

Da non dimenticare la creazione dell’oggetto sdf ( SimpleDataFormat ):

[sourcecode language="java"]
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyynHH:mm:ss");
[/sourcecode]


Con questa guida è tutto, se l’articolo vi è piaciuto condividete e restate sintonizzati per non perdervi alti tutorial sul mondo Android.

Lascia un commento