GraphLib: Android библиотека с отворен код за графики

Графиките и графиките с данни са прекрасни инструменти за илюстриране на взаимоотношения, изобразяване на тенденции в данните и проследяване на целите във вашите приложения за Android. Видях това за себе си преди няколко години, когато един мой бивш студент спечели първо място в студентско състезание за мобилни приложения, спонсорирано от Асоциацията на изпълнителите на отбраната в Чарлстън. Ключова характеристика на печелившото приложение „Диабет и аз“ беше възможността да се графират дневните нива на захар.

Като друг пример, помислете за приложение за проследяване на тежестта, което начертава напредъка спрямо целта. Фигура 1 илюстрира как такова приложение може да изглежда на телефон с Android. Фигурата използва червена графика за показване на средните месечни тегла за 2017 г. Тя показва целевото тегло като зелена права линия отдолу. (Въпреки че стойностите на данните, показани в линейната графика, са хипотетични, те са реалистични по отношение на автора на тази статия.)

Джон И. Мур

В тази статия ще използвам библиотеката си с отворен код, GraphLib, за да демонстрирам основите на графирането на математически функции в Android. Това не е същата графична библиотека, която моят студент използва за своето приложение. Всъщност е много по-опростен и лесен за използване.

изтегляне Изтегляне GraphLib Вземете изходния код за графичната библиотека с отворен код за Android, представена в тази статия. Създадено от Джон И. Мур.

Преглед на GraphLib

GraphLibсе състои от един интерфейс и осем класа. Три от тези класове са вътрешни за библиотеката и имат само пакетен достъп, така че няма да е необходимо да ги разбирате, за да използвате GraphLib. Два от останалите класове имат много проста функционалност, а останалите не е трудно да се вземат.

По-долу ще опиша интерфейса GraphLib и всеки от неговите осем класа. Имайте предвид, че използвах функции на Java 8 като функционални интерфейси и ламбда изрази за разработване и тестване на библиотеката, но е сравнително лесно да модифицирам тези функции за по-ранни версии на Java.

Функционалният интерфейс на GraphLib

Както е показано в Листинг 1, интерфейсът Functionима само един абстрактен метод и следователно е функционален интерфейс. Имайте предвид, че този интерфейс е приблизително еквивалентен на Java 8 DoubleUnaryOperator, намерен в пакета java.util.function. Разликата е, че Functionне използва никакви функции на Java 8, различни от анотацията @FunctionalInterface. Премахването на тази анотация е единствената промяна, необходима, за да стане Functionинтерфейсът съвместим с по-ранните версии на Java.

Списък 1. Функция на интерфейса

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

Изучаване на ламбда изрази

Ламбда изразите, известни също като затваряния, функционални литерали или просто ламбда, описват набор от функции, дефинирани в Заявка за спецификация на Java (JSR) 335. По-малко официални въведения в ламбда изразите са предоставени в раздел от последната версия на урока за Java; в статията на JavaWorld „Програмиране на Java с ламбда изрази“ и в няколко статии от Брайън Гьотц, „Състояние на ламбда“ и „Състояние на ламбда: издание на библиотеки“.

Класове GraphLib

Класовете Pointи Labelса относително прости: Pointкапсулира двойка двойни стойности, представляващи точка в x, y- равнината, и Labelкапсулира двойна стойност и низ, където двойната стойност представлява точка на ос и низът се използва за обозначаване на това точка. Примерът на фигура 1 използва точки, за да опише линейната графика и етикетите за оста в долната част, показващи еднобуквени съкращения за месеците. Ще дам още примери, илюстриращи използването на тези класове по-късно в статията.

Класовете GraphFunction, GraphPointsи ScreenPointса не само много прости, те също са вътрешни за библиотеката и имат само достъп до пакети. Всъщност не е нужно да разбирате тези класове, за да използвате библиотеката, затова ще ги опиша накратко тук:

  • GraphFunctionкапсулира функция (т.е. клас, който реализира интерфейс Function) и цвят, използван за изчертаване на тази функция.
  • GraphPointsкапсулира списък с точки заедно с цвят, използван за нанасянето им. Този клас се използва вътрешно както за нанасяне на точки, така и за чертане на линейни графики.
  • ScreenPointкапсулира двойка целочислени стойности, представляващи пикселни координати на екрана на устройство с Android. Този клас е подобен на, но по-опростен от Android класа Pointв пакет android.graphics.

Предоставих изходния код за тези класове, в случай че се интересувате от подробностите.

Останалите три класи в библиотеката GraphLib са Graph, Graph.Builderи GraphView. Важно е да разберете ролята, която всеки от тях играе в приложение за Android.

Класът Graphсъдържа информация за цветовете, точките, етикетите, графиките и т.н., които трябва да бъдат изчертани, но по същество е независима от графичните детайли на Android. Въпреки че Graphима много полета, всички те имат стойности по подразбиране и затова има смисъл да се използва моделът Builder, за да се създадат екземпляри от този клас. Класът Graphсъдържа вложен статичен подклас с име Builder, който се използва за създаване на Graphобекти.

Двете класи Graphи Graph.Builderвървят ръка за ръка, от гледна точка на разработчика, и следва да се разбират, по същество, като едно цяло. Всъщност трябва само да разберете как да използвате вложения клас Builderза създаване на Graphобект. Разработчиците всъщност не правят нищо директно с Graphобект, след като е създаден, освен да го предадат на GraphViewобект, който върши работата по показване на всичко на устройство с Android.

Листинг 2 обобщава методите, налични в класа Graph.Builder. По-късните примери ще илюстрират как да използвате шаблона на Builder за създаване на Graphобекти. Засега е достатъчно да се отбележи, че освен конструктора по подразбиране (първи ред в листинг 2) и build()метода (последен ред в листинг 2), всички други методи връщат Builderобекта. Това прави възможно верижните извиквания към методите на конструктора.

Листинг 2. Резюме на методите в клас 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() 

В листинг 2 ще забележите, че много от методите са претоварени, за да приемат масиви от обекти или списъци с обекти. Предпочитам масивите пред списъците за примери в тази статия, просто защото е много по-лесно да се инициализират масиви, но GraphLibподдържа и двете. Java 9 обаче ще съдържа удобни фабрични методи за колекции, като по този начин премахва това малко предимство за масивите. Ако Java 9 беше широко използвана по времето на тази статия, щях да предпочета списъци пред масиви и в двата, GraphLibи в по-късните примери.

Моделът на Builder

За да научите повече за модела на Builder, вижте второто издание на Effective Java от Joshua Bloch или статията за JavaWorld „Твърде много параметри в методите на Java, част 3: Модел на Builder“ от Dustin Marx.

Класовете на потребителския интерфейс в Android се наричат изгледи , а класът Viewв пакета android.viewе основният градивен елемент за компонентите на потребителския интерфейс. Изгледът заема правоъгълна област на екрана и отговаря за рисуването и обработката на събитията. От гледна точка на наследяването, класът Viewе клас предшественик не само на контролите на потребителския интерфейс (бутони, текстови полета и т.н.), но и на оформления, които са невидими групи на изглед, които са отговорни главно за подреждането на техните дъщерни компоненти.

Класът GraphViewразширява класа Viewи е отговорен за показване на информацията, капсулирана в a, Graphна екрана на устройство с Android. По този начин класът GraphViewе мястото, където се извършва цялото рисуване.

Използване на GraphLib

Има два подхода за създаване на потребителски интерфейси за Android: процедурен подход (в рамките на изходния код на Java) или декларативен подход (в XML файл). И двете са валидни, но консенсусът е да се използва декларативният подход, доколкото е възможно. Използвал съм декларативен подход за моите примери.

Има пет основни стъпки за използване на GraphLibбиблиотеката. Преди да започнете, изтеглете компилирания изходен код на Java за библиотеката GraphLib. 

изтегляне Изтегляне на GraphLib.jar Вземете компилирания изходен код на Java за GraphLib. Създадено от Джон И. Мур.

Стъпка 1. Направете graphlib.jar достъпен за вашия 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"); 

Фигура 2 показва резултата от стартирането на това приложение на устройство с Android.

Джон И. Мур

Използване на GraphLib в приложения за Android

В останалата част от статията ще се съсредоточа върху реалното използване на библиотеката GraphLib при разработването на приложения за Android. Ще представя седем примера с кратки описания и извадки от изходния код. Обърнете внимание, че списъците с Java кодове за тези примери са фокусирани върху използването Graph.Builderза създаване на подходящ Graphобект. Обажданията до findViewById(),, setGraph()и setTitle()т.н. биха били подобни на показаните в Листинг 5 и не са включени в списъците с кодове.