Programmering

GraphLib: Et open source Android-bibliotek til grafer

Grafer og dataplots er vidunderlige værktøjer til at illustrere forhold, skildre datatendenser og spore mål i dine Android-applikationer. Jeg så dette for mig selv for flere år siden, da en tidligere studerende af mig vandt førstepladsen i en mobilappkonkurrence for studerende sponsoreret af Charleston Defense Contractors Association. Et nøglefunktion i den vindende app, "Diabetes og mig", var evnen til at tegne daglige sukkerindhold.

Som et andet eksempel kan du overveje en vægt-tracking-applikation, der tegner fremskridt i forhold til en målvægt. Figur 1 illustrerer, hvordan en sådan applikation kan se ud på en Android-telefon. Figuren bruger en rød linjegraf til at vise gennemsnitlige månedlige vægte for året 2017. Den viser målvægten som en grøn lige linje nær bunden. (Selvom dataværdierne vist i linjediagrammet er hypotetiske, er de realistiske for forfatteren af ​​denne artikel.)

John I. Moore

I denne artikel bruger jeg mit open source-bibliotek, GraphLib, til at demonstrere det grundlæggende ved graftegning af matematiske funktioner i Android. Det er ikke det samme grafbibliotek, som min studerende brugte til sin applikation. Faktisk er det meget enklere og lettere at bruge.

download Download GraphLib Få kildekoden til open source Android-grafbiblioteket, der blev introduceret i denne artikel. Oprettet af John I. Moore.

Oversigt over GraphLib

GraphLib består af en grænseflade og otte klasser. Tre af disse klasser er interne i biblioteket og har kun pakkeadgang, så du behøver ikke forstå dem for at kunne bruge GraphLib. To af de resterende klasser har meget enkel funktionalitet, og resten er ikke svært at hente.

Nedenfor vil jeg beskrive GraphLib-grænsefladen og hver af dens otte klasser. Bemærk, at jeg brugte Java 8-funktioner såsom funktionelle grænseflader og lambda-udtryk til at udvikle og teste biblioteket, men det er relativt ligetil at ændre disse funktioner til tidligere versioner af Java.

GraphLibs funktionelle interface

Som vist i liste 1, interface Fungere har kun en abstrakt metode og er derfor en funktionel grænseflade. Bemærk, at denne grænseflade stort set svarer til Java 8'er DoubleUnaryOperator, findes i pakken java.util.function. Forskellen er, at Fungere bruger ikke andre Java 8-funktioner end kommentaren @FunktionelInterface. Fjernelse af denne kommentar er den eneste nødvendige ændring for at foretage Fungere interface kompatibel med tidligere versioner af Java.

Notering 1. interface Funktion

 pakke com.softmoore.android.graphlib; @FunctionalInterface offentlig grænseflade Funktion {offentlig dobbelt anvendelse (dobbelt x); } 

At lære om lambda-udtryk

Lambda-udtryk, også kendt som lukninger, funktionsbogstaver eller blot lambdas, beskriver et sæt funktioner defineret i Java Specification Request (JSR) 335. Mindre formelle introduktioner til lambda-udtryk findes i et afsnit i den nyeste version af Java Tutorial; i JavaWorld-artiklen "Java-programmering med lambda-udtryk" og i et par artikler af Brian Goetz, "State of the lambda" og "State of the lambda: Libraries edition."

GraphLib klasser

Klasser Punkt og Etiket er relativt enkle: Punkt indkapsler et par dobbeltværdier, der repræsenterer et punkt i x, y-plan, og Etiket indkapsler en dobbelt værdi og en streng, hvor den dobbelte værdi repræsenterer et punkt på en akse, og strengen bruges til at mærke dette punkt. Eksemplet i figur 1 bruger punkter til at beskrive linjediagrammet og etiketterne for aksen i bunden, der viser forkortelser med et bogstav for månederne. Jeg giver flere eksempler, der illustrerer brugen af ​​disse klasser senere i artiklen.

Klasser Graffunktion, GraphPointsog ScreenPoint er ikke kun meget enkle, de er også interne i biblioteket og har kun pakkeadgang. Du behøver ikke rigtig forstå disse klasser for at bruge biblioteket, så jeg beskriver dem bare kort her:

  • Graffunktion indkapsler en funktion (dvs. en klasse, der implementerer interface Fungere) og en farve, der bruges til at tegne denne funktion.
  • GraphPoints indkapsler en liste over punkter sammen med en farve, der bruges til at plotte dem. Denne klasse bruges internt til både tegning af punkter og tegning af linjegrafer.
  • ScreenPoint indkapsler et par heltalværdier, der repræsenterer pixelkoordinater på skærmen på en Android-enhed. Denne klasse ligner, men er enklere end Android-klassen Punkt i pakke android.graphics.

Jeg har angivet kildekoden til disse klasser, hvis du er interesseret i detaljerne.

De tre resterende klasser i GraphLib-biblioteket er Kurve, Graf.Byggerog GraphView. Det er vigtigt at forstå den rolle, som hver af dem spiller i en Android-applikation.

Klasse Kurve indeholder oplysninger om farver, punkter, etiketter, grafer osv., der skal tegnes, men er i det væsentlige uafhængig af Android-grafikdetaljer. Mens Kurve har mange felter, de har alle standardværdier, og derfor giver det mening at bruge Builder-mønsteret til at oprette forekomster af denne klasse. Klasse Kurve indeholder en indlejret statisk underklasse navngivet Bygger, som bruges til at oprette Kurve genstande.

De to klasser Kurve og Graf.Bygger gå sammen fra en udviklers perspektiv og skal i det væsentlige forstås som en. I virkeligheden behøver du kun at forstå, hvordan du bruger den indlejrede klasse Bygger at oprette en Kurve objekt. Udviklere gør ikke rigtig noget direkte med en Kurve objekt, efter at det er oprettet, bortset fra at videregive det til en GraphView objekt, der gør arbejdet med at vise alt på en Android-enhed.

Liste 2 opsummerer de tilgængelige metoder i klassen Graf.Bygger. Senere eksempler illustrerer, hvordan man bruger Builder-mønsteret til at oprette Kurve genstande. For nu er det nok at bemærke, at andet end standardkonstruktøren (første linje i liste 2) og bygge () metode (sidste linje i liste 2), returnerer alle andre metoder Bygger objekt. Dette gør det muligt at kæde opkald til byggemetoder.

Liste 2. Oversigt over metoder i klassen Graf.Bygger

 public Builder () public Builder addFunction (Function function, int graphColor) public Builder addFunction (Function function) public Builder addPoints (Point [] points, int pointColor) public Builder addPoints (List points, int pointColor) public Builder addPoints (Point [] point) public Builder addPoints (List points) public Builder addLineGraph (Point [] points, int lineGraphColor) public Builder addLineGraph (List points, int lineGraphColor) public Builder addLineGraph (Point [] points) public Builder addLineGraph (List points) public Builder setBackgroundColor (int bgColor) public Builder setAxesColor (int axesColor) public Builder setFunctionColor (int functColor) public Builder setPointColor (int pointColor) public Builder setWorldCoordinates (double xMin, double xMax, double yMin, double yMax) public Builder setAxes ) public Builder setXTicks (double [] xTicks) public Builder setXTicks (List xTicks) public Builder setYTicks (double [] yTicks) public Builder setYTicks (List yT icks) public Builder setXLabels (Label [] xLabels) public Builder setXLabels (List xLabels) public Builder setYLabels (Label [] yLabels) public Builder setYLabels (List yLabels) public Graph build () 

Du vil bemærke i Listing 2, at mange af metoderne er overbelastede til at acceptere enten arrays af objekter eller lister over objekter. Jeg foretrækker arrays frem for lister for eksempler i denne artikel, simpelthen fordi det er meget lettere at initialisere arrays, men GraphLib understøtter begge dele. Java 9 vil imidlertid indeholde bekvemme fabriksmetoder til samlinger og derved fjerne denne lille fordel for arrays. Var Java 9 i udbredt anvendelse på tidspunktet for denne artikel, ville jeg have foretrukket lister frem for arrays i begge GraphLib og de senere eksempler.

Builder-mønsteret

For at lære mere om Builder-mønsteret, se den anden udgave af Effective Java af Joshua Bloch eller JavaWorld-artiklen "For mange parametre i Java-metoder, del 3: Builder-mønster" af Dustin Marx.

Brugergrænsefladesklasser i Android kaldes synspunkterog klasse Udsigt i pakke android.view er den grundlæggende byggesten til brugergrænsefladekomponenter. En visning optager et rektangulært område på skærmen og er ansvarlig for tegning og håndtering af begivenheder. Fra et arveperspektiv klasse Udsigt er en forfædre klasse ikke kun kontrolelementer til brugergrænseflader (knapper, tekstfelter osv.), men også layout, som er usynlige visningsgrupper, der primært er ansvarlige for at arrangere deres underordnede komponenter.

Klasse GraphView udvider klassen Udsigt og er ansvarlig for at vise de oplysninger, der er indkapslet i a Kurve på skærmen på en Android-enhed. Således klasse GraphView er hvor hele tegningen finder sted.

Brug af GraphLib

Der er to tilgange til oprettelse af brugergrænseflader til Android: en proceduremæssig tilgang (inden for Java-kildekoden) eller en deklarativ tilgang (i en XML-fil). Enten er gyldig, men konsensus er at bruge den deklarative tilgang så meget som muligt. Jeg har brugt en deklarativ tilgang til mine eksempler.

Der er fem grundlæggende trin til brug af GraphLib bibliotek. Før du starter, skal du downloade den kompilerede Java-kildekode til GraphLib-biblioteket.

download Download GraphLib.jar Få den kompilerede Java-kildekode til GraphLib. Oprettet af John I. Moore.

Trin 1. Gør graphlib.jar tilgængelig for dit Android-projekt

Opret et nyt projekt ved hjælp af Android Studio, og kopier JAR-filen graphlib.jar til libs underkatalog til dit projekts app vejviser. Skift mappestrukturen fra i Android Studio Android til Projekt. Dernæst i libs mappe (indlejret i app mappe), højreklik på JAR-filen og klik på Tilføj som bibliotek. Denne sidste handling tilføjer JAR-filen i afhængighedsafsnittet i din app build.gradle fil. Se "Sådan tilføjes en krukke i eksterne biblioteker i Android Studio", hvis du har brug for hjælp til dette trin.

Trin 2. Opret en Android-aktivitet, der bruger GraphLib

I Android-applikationer er en aktivitet repræsenterer en enkelt skærm med en brugergrænseflade. Aktiviteter defineres primært i to filer: en XML-fil, der erklærer UI-layoutet og komponenterne, og en Java-fil, der definerer runtime-funktionalitet såsom håndtering af begivenheder. Når et nyt projekt oprettes, opretter Android Studio normalt en standardaktivitet med navnet MainActivity. Brug denne aktivitet, eller opret en ny til din applikation.

Trin 3. Tilføj en GraphView til layoutet for aktiviteten

I XML-filen for aktivitetens layout erklærer du en GraphView modsætter sig på samme måde som du erklærer en knap eller en tekstvisning, bortset fra at du skal angive det fulde pakkenavn til GraphView. Liste 3 viser et uddrag fra en layoutfil, der erklærer en GraphView efterfulgt af en TextView som en del af et lodret lineært layout. Efter anbefalet praksis skal de faktiske værdier for bredden og højden af GraphView er defineret separat dimen ressourcefiler, hvor forskellige ressourcefiler giver værdier for forskellige skærmstørrelser / densiteter. (Bemærk: Jeg brugte 325 til begge værdier i eksemplerne nedenfor.)

Fortegnelse 3. Erklæring om en GraphView og en TextView i en layout-XML-fil

Trin 4. Importer biblioteksklasser til aktiviteten

Fortegnelse 4 viser listen over importerklæringer til en applikation, hvis biblioteksklasserne importeres individuelt. Listen over import kan forkortes til en enkelt linje som importer com.softmoore.android.graphlib. * hvis ønsket. Personligt foretrækker jeg at se den udvidede liste som vist i liste 4.

Fortegnelse 4. Importer bibliotekets klasser

 import com.softmoore.android.graphlib.Function; import com.softmoore.android.graphlib.Graph; import com.softmoore.android.graphlib.GraphView; import com.softmoore.android.graphlib.Label; import com.softmoore.android.graphlib.Point; 

Trin 5. Opret et grafobjekt, og tilføj det til GraphView

Liste 5 viser oprettelsen af ​​et simpelt grafobjekt - i dette tilfælde et grafobjekt, der bruger alle standardværdierne. Det indeholder i det væsentlige kun et sæt x- og y-akser, hvor værdierne på begge akser spænder fra 0 til 10. Noteringen indstiller også en titel til skærmen og tekst til tekstvisningen under grafen.

Fortegnelse 5. Opret et grafobjekt, og føj det til GraphView

 Grafgraf = ny Graph.Builder () .build (); GraphView graphView = findViewById (R.id.graph_view); graphView.setGraph (graf); setTitle ("Tom graf"); TextView textView = findViewById (R.id.graph_view_label); textView.setText ("Graf af akser"); 

Figur 2 viser resultatet af at køre denne applikation på en Android-enhed.

John I. Moore

Brug af GraphLib i Android-applikationer

For resten af ​​artiklen vil jeg fokusere på virkelige anvendelser af GraphLib-biblioteket i Android-applikationsudvikling. Jeg præsenterer syv eksempler med korte beskrivelser og kildekodeuddrag. Bemærk, at Java-kodelisterne for disse eksempler er fokuseret på brug Graf.Bygger for at skabe det rette Kurve objekt. Opfordrer til findViewById (), setGraph (), setTitle ()osv. svarer til dem, der vises i liste 5 og er ikke inkluderet i kodelisterne.

$config[zx-auto] not found$config[zx-overlay] not found