GraphLib: Eine Open-Source-Android-Bibliothek für Grafiken
Grafiken und Datenplots sind wunderbare Werkzeuge zur Veranschaulichung von Beziehungen, zur Darstellung von Datentrends und zur Verfolgung von Zielen in Ihren Android-Anwendungen. Ich habe das vor einigen Jahren selbst gesehen, als ein ehemaliger Student von mir den ersten Platz bei einem von der Charleston Defense Contractors Association gesponserten Wettbewerb für mobile Apps für Studenten gewann. Ein wichtiges Merkmal der Gewinner-App "Diabetes and Me" war die Möglichkeit, den täglichen Zuckergehalt grafisch darzustellen.
Betrachten Sie als weiteres Beispiel eine Anwendung zur Gewichtsverfolgung, die den Fortschritt anhand eines Zielgewichts aufzeichnet. Abbildung 1 zeigt, wie eine solche Anwendung auf einem Android-Telefon aussehen könnte. Die Abbildung verwendet ein rotes Liniendiagramm, um die durchschnittlichen monatlichen Gewichte für das Jahr 2017 anzuzeigen. Sie zeigt das Zielgewicht als grüne gerade Linie in der Nähe des unteren Bereichs. (Obwohl die im Liniendiagramm angezeigten Datenwerte hypothetisch sind, sind sie für den Autor dieses Artikels realistisch.)

In diesem Artikel werde ich meine Open-Source-Bibliothek GraphLib verwenden, um die Grundlagen der grafischen Darstellung mathematischer Funktionen in Android zu demonstrieren. Es ist nicht dieselbe Grafikbibliothek, die mein Schüler für seine Anwendung verwendet hat. In der Tat ist es viel einfacher und einfacher zu bedienen.
download Download GraphLib Ruft den Quellcode für die in diesem Artikel vorgestellte Open Source-Grafikbibliothek für Android ab. Erstellt von John I. Moore.Übersicht über GraphLib
GraphLib
besteht aus einer Schnittstelle und acht Klassen. Drei dieser Klassen sind bibliotheksintern und haben nur Paketzugriff, sodass Sie sie nicht verstehen müssen, um GraphLib verwenden zu können. Zwei der verbleibenden Klassen haben eine sehr einfache Funktionalität, und der Rest ist nicht schwer zu erlernen.
Im Folgenden werde ich die GraphLib-Schnittstelle und jede ihrer acht Klassen beschreiben. Beachten Sie, dass ich Java 8-Funktionen wie Funktionsschnittstellen und Lambda-Ausdrücke zum Entwickeln und Testen der Bibliothek verwendet habe. Es ist jedoch relativ einfach, diese Funktionen für frühere Java-Versionen zu ändern.
Funktionsschnittstelle von GraphLib
Wie in Listing 1 gezeigt, hat die Schnittstelle Function
nur eine abstrakte Methode und ist daher eine funktionale Schnittstelle. Beachten Sie, dass diese Schnittstelle in etwa den DoubleUnaryOperator
im Paket enthaltenen Java 8-Schnittstellen entspricht java.util.function
. Der Unterschied besteht darin, dass Function
keine anderen Java 8-Funktionen als die Anmerkung verwendet werden @FunctionalInterface
. Das Entfernen dieser Anmerkung ist die einzige Änderung, die erforderlich ist, um die Function
Schnittstelle mit früheren Java-Versionen kompatibel zu machen .
Listing 1. Schnittstelle Funktion
package com.softmoore.android.graphlib; @FunctionalInterface public interface Function { public double apply(double x); }
Lernen über Lambda-Ausdrücke
Lambda-Ausdrücke, auch als Closures, Funktionsliterale oder einfach Lambdas bezeichnet, beschreiben eine Reihe von Funktionen, die in Java Specification Request (JSR) 335 definiert sind. Weniger formale Einführungen in Lambda-Ausdrücke finden Sie in einem Abschnitt der neuesten Version des Java-Lernprogramms. im JavaWorld-Artikel "Java-Programmierung mit Lambda-Ausdrücken" und in einigen Artikeln von Brian Goetz, "State of the Lambda" und "State of the Lambda: Libraries Edition".
GraphLib-Klassen
Klassen Point
und Label
sind relativ einfach: Point
kapselt ein Paar von Doppelwerten, die einen Punkt in der x-, y- Ebene darstellen, und Label
kapselt einen Doppelwert und eine Zeichenfolge, wobei der Doppelwert einen Punkt auf einer Achse darstellt und die Zeichenfolge verwendet wird, um diesen zu kennzeichnen Punkt. In dem Beispiel in Abbildung 1 werden Punkte verwendet, um das Liniendiagramm und die Beschriftungen für die Achse unten zu beschreiben, wobei Abkürzungen mit einem Buchstaben für die Monate angezeigt werden. Ich werde später in diesem Artikel weitere Beispiele zur Verwendung dieser Klassen bereitstellen.
Klassen GraphFunction
, GraphPoints
und ScreenPoint
sind nicht nur sehr einfach, sie sind in die Bibliothek auch intern und haben nur Zugang zu verpacken. Sie müssen diese Klassen nicht wirklich verstehen, um die Bibliothek nutzen zu können. Deshalb werde ich sie hier nur kurz beschreiben:
GraphFunction
kapselt eine Funktion (dh eine Klasse, die die Schnittstelle implementiertFunction
) und eine Farbe, die zum Zeichnen dieser Funktion verwendet wird.GraphPoints
kapselt eine Liste von Punkten zusammen mit einer Farbe, mit der sie gezeichnet werden. Diese Klasse wird intern sowohl zum Zeichnen von Punkten als auch zum Zeichnen von Liniendiagrammen verwendet.ScreenPoint
kapselt ein Paar ganzzahliger Werte, die Pixelkoordinaten auf dem Bildschirm eines Android-Geräts darstellen. Diese Klasse ähnelt der Android-KlassePoint
im Paket, ist jedoch einfacherandroid.graphics
.
Ich habe den Quellcode für diese Klassen bereitgestellt, falls Sie an den Details interessiert sind.
Die drei übrigen Klassen in der Bibliothek GraphLib sind Graph
, Graph.Builder
und GraphView
. Es ist wichtig zu verstehen, welche Rolle jeder von ihnen in einer Android-Anwendung spielt.
Die Klasse Graph
enthält Informationen zu den zu zeichnenden Farben, Punkten, Beschriftungen, Grafiken usw., ist jedoch im Wesentlichen unabhängig von den Details der Android-Grafik. Obwohl Graph
es viele Felder gibt, haben sie alle Standardwerte. Daher ist es sinnvoll, das Builder-Muster zum Erstellen von Instanzen dieser Klasse zu verwenden. Die Klasse Graph
enthält eine verschachtelte statische Unterklasse mit dem Namen Builder
, mit der Graph
Objekte erstellt werden.
Die beiden Klassen Graph
und Graph.Builder
gehen zusammen, aus der Sicht des Entwicklers und sollen im Wesentlichen verstanden werden, als eine. In Wahrheit müssen Sie nur verstehen, wie Sie die verschachtelte Klasse Builder
zum Erstellen eines Graph
Objekts verwenden. Entwickler tun nichts direkt mit einem Graph
Objekt, nachdem es erstellt wurde, außer es an ein GraphView
Objekt zu übergeben, das alles auf einem Android-Gerät anzeigt.
Listing 2 fasst die in der Klasse verfügbaren Methoden zusammen Graph.Builder
. In späteren Beispielen wird veranschaulicht, wie das Builder-Muster zum Erstellen von Graph
Objekten verwendet wird. Im Moment genügt es zu beachten, dass außer dem Standardkonstruktor (erste Zeile in Listing 2) und der build()
Methode (letzte Zeile in Listing 2) alle anderen Methoden das Builder
Objekt zurückgeben. Auf diese Weise können Aufrufe an Builder-Methoden verkettet werden.
Listing 2. Zusammenfassung der Methoden in der Klasse Graph.Builder
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[] points) 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(double axisX, double axisY) public Builder setXTicks(double[] xTicks) public Builder setXTicks(List xTicks) public Builder setYTicks(double[] yTicks) public Builder setYTicks(List yTicks) public Builder setXLabels(Label[] xLabels) public Builder setXLabels(List xLabels) public Builder setYLabels(Label[] yLabels) public Builder setYLabels(List yLabels) public Graph build()
In Listing 2 werden Sie feststellen, dass viele der Methoden überladen sind, um entweder Arrays von Objekten oder Listen von Objekten zu akzeptieren. Ich bevorzuge Arrays gegenüber Listen für Beispiele in diesem Artikel, einfach weil es viel einfacher ist, Arrays zu initialisieren, aber GraphLib
beide unterstützt. Java 9 enthält jedoch Convenience-Factory-Methoden für Sammlungen, wodurch dieser kleine Vorteil für Arrays beseitigt wird. Wäre Java 9 zum Zeitpunkt dieses Artikels weit verbreitet, hätte ich Listen in beiden GraphLib
und den späteren Beispielen Arrays vorgezogen .
Das Builder-Muster
Weitere Informationen zum Builder-Muster finden Sie in der zweiten Ausgabe von Effective Java von Joshua Bloch oder im JavaWorld-Artikel "Zu viele Parameter in Java-Methoden, Teil 3: Builder-Muster" von Dustin Marx.
User interface classes in Android are called views, and class View
in package android.view
is the basic building block for user interface components. A view occupies a rectangular area on the screen, and is responsible for drawing and event handling. From an inheritance perspective, class View
is an ancestor class not only of user interface controls (buttons, text fields, etc.) but also of layouts, which are invisible view groups that are primarily responsible for arranging their child components.
Class GraphView
extends class View
and is responsible for displaying the information encapsulated in a Graph
on the screen of an Android device. Thus, class GraphView
is where all the drawing takes place.
Using GraphLib
Es gibt zwei Ansätze zum Erstellen von Benutzeroberflächen für Android: einen prozeduralen Ansatz (innerhalb des Java-Quellcodes) oder einen deklarativen Ansatz (in einer XML-Datei). Beides ist gültig, aber der Konsens besteht darin, den deklarativen Ansatz so weit wie möglich zu verwenden. Ich habe für meine Beispiele einen deklarativen Ansatz verwendet.
Es gibt fünf grundlegende Schritte zur Verwendung der GraphLib
Bibliothek. Laden Sie vor dem Start den kompilierten Java-Quellcode für die GraphLib-Bibliothek herunter.
Schritt 1. Stellen Sie graphlib.jar für Ihr Android-Projekt zur Verfügung
Create a new project using Android Studio and copy the JAR file graphlib.jar
to the libs
subdirectory of your project's app
directory. In Android Studio, switch the folder structure from Android to Project. Next, in the libs
folder (nested within the app
folder), right-click on the JAR file and click on Add as library. This last action will add the JAR file in the dependencies section of your app's build.gradle
file. See "How to add a jar in external libraries in Android Studio" if you need help with this step.
Step 2. Create an Android activity that will use GraphLib
In Android applications, an activity represents a single screen with a user interface. Activities are defined primarily in two files: an XML file that declares the UI layout and components, and a Java file that defines runtime functionality such as event handling. When a new project is created, Android Studio usually creates a default activity named MainActivity
. Use this activity or create a new one for your application.
Step 3. Add a GraphView to the layout for the activity
In the XML file for the activity's layout, you will declare a GraphView
object in much the same way that you declare a button or a text view, except that you need to provide the full package name for the GraphView
. Listing 3 shows an excerpt from a layout file that declares a GraphView
followed by a TextView
as part of a vertical linear layout. Following recommended practice, the actual values for the width and height of the GraphView
are defined in separate dimen
resource files, where different resource files provide values for different screen sizes/densities. (Note: I used 325 for both values in the examples below.)
Listing 3. Declaring a GraphView and a TextView in a layout XML file
Step 4. Import the library classes into the activity
Listing 4 shows the list of import statements for an application if the library classes are imported individually. The list of imports can be abbreviated to a single line as import com.softmoore.android.graphlib.*
if desired. Personally, I prefer to see the expanded list as shown in Listing 4.
Listing 4. Import the library classes
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;
Step 5. Create a Graph object and add it to the GraphView
Listing 5 shows the creation of a simple graph object--in this case a graph object that uses all of the default values. It essentially contains only a set of x- and y-axes, where the values on both axes range from 0 to 10. The listing also sets a title for the screen and text for the text view below the graph.
Listing 5. Create a Graph object and add it to the GraphView
Graph graph = new Graph.Builder() .build(); GraphView graphView = findViewById(R.id.graph_view); graphView.setGraph(graph); setTitle("Empty Graph"); TextView textView = findViewById(R.id.graph_view_label); textView.setText("Graph of Axes");
Abbildung 2 zeigt das Ergebnis der Ausführung dieser Anwendung auf einem Android-Gerät.

Verwenden von GraphLib in Android-Anwendungen
Im weiteren Verlauf des Artikels werde ich mich auf die reale Verwendung der GraphLib-Bibliothek in der Android-Anwendungsentwicklung konzentrieren. Ich werde sieben Beispiele mit kurzen Beschreibungen und Quellcode-Auszügen vorstellen. Beachten Sie, dass die Java-Codelisten für diese Beispiele darauf ausgerichtet sind Graph.Builder
, das entsprechende Graph
Objekt zu erstellen . Anrufe zu findViewById()
, setGraph()
, setTitle()
usw. würden wie in Listing ähnlich 5 und sind nicht in den Codebeispielen enthalten.