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.