GraphLib: une bibliothèque Android open source pour les graphiques

Les graphiques et les tracés de données sont de merveilleux outils pour illustrer les relations, décrire les tendances des données et suivre les objectifs dans vos applications Android. J'ai vu cela par moi-même il y a plusieurs années, lorsqu'un de mes anciens élèves a remporté la première place d'un concours d'applications mobiles pour étudiants parrainé par la Charleston Defense Contractors Association. Une caractéristique clé de l'application gagnante, "Diabetes and Me", était la possibilité de représenter graphiquement les niveaux de sucre quotidiens.

Comme autre exemple, considérons une application de suivi du poids qui trace les progrès par rapport à un objectif de poids. La figure 1 illustre à quoi pourrait ressembler une telle application sur un téléphone Android. La figure utilise un graphique linéaire rouge pour montrer les poids mensuels moyens pour l'année 2017. Il montre le poids de l'objectif sous la forme d'une ligne droite verte près du bas. (Bien que les valeurs de données affichées dans le graphique linéaire soient hypothétiques, elles sont réalistes pour l'auteur de cet article.)

John I. Moore

Dans cet article, j'utiliserai ma bibliothèque open source, GraphLib, pour démontrer les bases de la représentation graphique des fonctions mathématiques sous Android. Ce n'est pas la même bibliothèque de graphiques que mon élève a utilisée pour son application. En fait, c'est beaucoup plus simple et plus facile à utiliser.

télécharger Télécharger GraphLib Obtenez le code source de la bibliothèque graphique Android open source présentée dans cet article. Créé par John I. Moore.

Présentation de GraphLib

GraphLibse compose d'une interface et de huit classes. Trois de ces classes sont internes à la bibliothèque et n'ont qu'un accès aux packages, vous n'aurez donc pas besoin de les comprendre pour utiliser GraphLib. Deux des classes restantes ont des fonctionnalités très simples et les autres ne sont pas difficiles à saisir.

Ci-dessous, je décrirai l'interface GraphLib et chacune de ses huit classes. Notez que j'ai utilisé des fonctionnalités de Java 8 telles que des interfaces fonctionnelles et des expressions lambda pour développer et tester la bibliothèque, mais il est relativement simple de modifier ces fonctionnalités pour les versions antérieures de Java.

Interface fonctionnelle de GraphLib

Comme le montre le Listing 1, l'interface Functionn'a qu'une seule méthode abstraite et est, par conséquent, une interface fonctionnelle. Notez que cette interface est à peu près équivalente à celle de Java 8 DoubleUnaryOperator, trouvée dans le package java.util.function. La différence est que Functionn'utilise aucune fonctionnalité Java 8 autre que l'annotation @FunctionalInterface. La suppression de cette annotation est la seule modification nécessaire pour rendre l' Functioninterface compatible avec les versions antérieures de Java.

Liste 1. Fonction d'interface

 package com.softmoore.android.graphlib; @FunctionalInterface public interface Function { public double apply(double x); } 

En savoir plus sur les expressions lambda

Les expressions lambda, également appelées fermetures, littéraux de fonction ou simplement lambdas, décrivent un ensemble de fonctionnalités définies dans Java Specification Request (JSR) 335. Des introductions moins formelles aux expressions lambda sont fournies dans une section de la dernière version du tutoriel Java; dans l'article JavaWorld «Programmation Java avec des expressions lambda» et dans quelques articles de Brian Goetz, «State of the lambda» et «State of the lambda: Libraries edition».

Classes GraphLib

Classes Pointet Labelsont relativement simples: Pointencapsule une paire de valeurs doubles représentant un point dans le plan x, y , et Labelencapsule une valeur double et une chaîne, où la valeur double représente un point sur un axe et la chaîne est utilisée pour étiqueter cela point. L'exemple de la figure 1 utilise des points pour décrire le graphique linéaire et les étiquettes de l'axe en bas, montrant les abréviations d'une lettre pour les mois. Je fournirai plus d'exemples illustrant l'utilisation de ces classes plus loin dans l'article.

Les classes GraphFunction, GraphPointset ScreenPointne sont pas seulement très simples, elles sont également internes à la bibliothèque et n'ont accès qu'aux packages. Vous n'avez pas vraiment besoin de comprendre ces classes pour utiliser la bibliothèque, je vais donc les décrire brièvement ici:

  • GraphFunctionencapsule une fonction (c'est-à-dire une classe qui implémente l'interface Function) et une couleur utilisée pour dessiner cette fonction.
  • GraphPointsencapsule une liste de points avec une couleur utilisée pour les tracer. Cette classe est utilisée en interne pour tracer des points et dessiner des graphiques linéaires.
  • ScreenPointencapsule une paire de valeurs entières représentant les coordonnées des pixels sur l'écran d'un appareil Android. Cette classe est similaire mais plus simple que la classe Android Pointdans package android.graphics.

J'ai fourni le code source de ces classes au cas où vous seriez intéressé par les détails.

Les trois autres classes dans la bibliothèque graphlib sont Graph, Graph.Builderet GraphView. Il est important de comprendre le rôle que chacun d'eux joue dans une application Android.

La classe Graphcontient des informations sur les couleurs, les points, les étiquettes, les graphiques, etc., à dessiner, mais est essentiellement indépendante des détails graphiques Android. Bien qu'il Graphcomporte de nombreux champs, ils ont tous des valeurs par défaut, et il est donc logique d'utiliser le modèle Builder pour créer des instances de cette classe. La classe Graphcontient une sous-classe statique imbriquée nommée Builder, qui est utilisée pour créer des Graphobjets.

Les deux classes Graphet Graph.Buildervont de pair, d'un point de vue du développeur, et doivent être compris, essentiellement, comme l' un. En vérité, il vous suffit de comprendre comment utiliser la classe imbriquée Builderpour créer un Graphobjet. Les développeurs ne font rien directement avec un Graphobjet après sa création, à part le transmettre à un GraphViewobjet, qui fait le travail de tout afficher sur un appareil Android.

Le listing 2 résume les méthodes disponibles en classe Graph.Builder. Des exemples ultérieurs illustreront comment utiliser le modèle Builder pour créer des Graphobjets. Pour l'instant, il suffit de noter qu'à part le constructeur par défaut (première ligne du Listing 2) et la build()méthode (dernière ligne du Listing 2), toutes les autres méthodes renvoient l' Builderobjet. Cela permet d'enchaîner les appels aux méthodes de générateur.

Listing 2. Résumé des méthodes en classe 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() 

Vous remarquerez dans le listing 2 que de nombreuses méthodes sont surchargées pour accepter soit des tableaux d'objets, soit des listes d'objets. Je donne la préférence aux tableaux sur les listes pour les exemples dans cet article, simplement parce qu'il est beaucoup plus facile d'initialiser les tableaux, mais GraphLibprend en charge les deux. Cependant, Java 9 contiendra des méthodes d'usine pratiques pour les collections, supprimant ainsi ce petit avantage pour les tableaux. Si Java 9 était largement utilisé au moment de cet article, j'aurais préféré les listes aux tableaux dans les deux GraphLibexemples et les derniers exemples.

Le modèle Builder

Pour en savoir plus sur le modèle Builder, consultez la deuxième édition de Effective Java de Joshua Bloch ou l'article JavaWorld «Trop de paramètres dans les méthodes Java, Partie 3: Modèle Builder» de 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

Il existe deux approches pour créer des interfaces utilisateur pour Android: une approche procédurale (dans le code source Java) ou une approche déclarative (dans un fichier XML). L'une ou l'autre est valable, mais le consensus est d'utiliser l'approche déclarative autant que possible. J'ai utilisé une approche déclarative pour mes exemples.

Il y a cinq étapes de base pour utiliser la GraphLibbibliothèque. Avant de commencer, téléchargez le code source Java compilé pour la bibliothèque GraphLib. 

télécharger Télécharger GraphLib.jar Obtenez le code source Java compilé pour GraphLib. Créé par John I. Moore.

Étape 1: rendez graphlib.jar disponible pour votre projet Android

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"); 

La figure 2 montre le résultat de l'exécution de cette application sur un appareil Android.

John I. Moore

Utilisation de GraphLib dans les applications Android

Pour le reste de l'article, je me concentrerai sur les utilisations réelles de la bibliothèque GraphLib dans le développement d'applications Android. Je vais présenter sept exemples avec de brèves descriptions et des extraits de code source. Notez que les listes de code Java pour ces exemples sont axées sur l'utilisation Graph.Builderpour créer l' Graphobjet approprié . Appels findViewById(), setGraph(), setTitle(), etc., seraient semblables à ceux indiqués dans la liste des 5 et ne sont pas inclus dans les listes de codes.