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 < 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.