Smarthome App #13: Sensorwerteverlauf anzeigen


02.06.2017  |  Tutorial, Smarthome App

Im heutigen Tutorial wird eine Activity angelegt, mit der der Verlauf der Sensorwerte in einem Diagramm dargestellt werden. Dabei wird für jeden Tag der jeweilge Höchst- & Tieftwert angezeigt. Der angezeigte Zeitintervall kann frei gewählt werden.

Bibliothek einbinden

Als erstes muss die benötigte Bibliothek eingebunden werden. Um Bibliotheken einbinden zu können, müssen Repositories hinzugefügt werden. Dazu öffnest du die Datei "build.gradle [Project: Smarthome]" und fügst dem Block "repositories" diese drei Zeilen hinzu:
mavenCentral()
maven{ url 'https://jitpack.io' }
jcenter{ url 'http://jcenter.bintray.com/' }
Als nächstes wird die Bibliothek für die Diagramme eingebunden. Dazu öffnest du die Datei "build.gradle [Module: mobile]" und fügst dem "dependencies"-Block die folgende Zeile hinzu:
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
Nun muss das Projekt mit den Gradle-Dateien synchronisiert werden. Klicke dazu in der gelben Leiste oben rechts auf "Sync now".
Synchronisiere das Projekt mit den Gradle-Dateien.

GraphActivity designen

Nun erstellst du eine neue Activity, indem du mit rechts auf eine Java-Datei klickst und New -> Activity -> Empty Activity" wählst. Gib ihr den Namen "GraphActivity" und klicke auf "Finish".
Erstelle die neue Activity.
Bevor die GraphActivity implementiert wird, wird die Layout-Datei bearbeitet. Öffne die Datei "activity_graph.xml" und ersetze den vohandenen Code mit dem folgenden:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    android:background="@color/layoutBackground"
    android:id="@+id/frame"
    tools:context="de.smarthome_blogger.smarthome.GraphActivity">

    <com.github.mikephil.charting.charts.LineChart
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/linechart"
        android:visibility="gone"></com.github.mikephil.charting.charts.LineChart>

    <include
        layout="@layout/loading_animation"
        android:visibility="gone"
        android:id="@+id/loading_animation"></include>

    <include
        layout="@layout/empty_item"
        android:visibility="gone"
        android:id="@+id/empty_item"></include>

</RelativeLayout>
Als nächstes klickst du mit rechts auf den Ordner "res -> menu" und wählst "New -> Menu resource file", um eine neue Menü-Datei zu erstellen.
Erstelle eine neue Menü-Datei.
Gib der Datei den Namen "activity_graph" und klicke auf "Ok". Füge dann in den menu-Tag der Menü-Datei den folgenden Code ein, um dem Menü einen Menüpunkt mit dem Text "Zeitraum ändern" hinzuzufügen:
<item android:id="@+id/change_period"
    android:title="Zeitraum &auml;ndern"
    android:orderInCategory="100"
    app:showAsAction="always"></item>

GraphActivity implementieren

Jetzt wechselst du zur Datei "GraphActivity.java" und fügst der Klasse über der Methode onCreate() ein paar neue Attribute hinzu:
private String location, devicetype, post_id, einheit;
private LineChart lineChart;
private ArrayList<GraphDayItem> dayList;

//F&uuml;r benutzerdefinierten Zeitraum
private final long dayMilliseconds = 60 * 60 * 24 * 1000;
private DateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
Anschließend klickst du mit rechts auf das Package "items" oder eine Klasse darin und wählst "New -> Java Class". Gib ihr den Namen "GraphDayItem" und klicke auf "Ok".
Erstelle die neue Klasse im Package
Die Klasse besitzt die Attribute "date", "minVal" und "maxVal", einen Konstruktor, der diese Attribute initialisiert und eine Getter-Methode für jedes der Attribute:
private String date;
private float minVal, maxVal;

public GraphDayItem(String date, float minVal, float maxVal){
    this.date = date;
    this.minVal = minVal;
    this.maxVal = maxVal;
}

/**
 * Gibt das Datum zur&uuml;ck
 * @return
 */
public String getDate(){
    return date;
}

/**
 * Gibt den minimalen Wert zur&uuml;ck
 * @return
 */
public float getMinVal(){
    return minVal;
}

/**
 * Gibt den maximalen Wert zur&uuml;ck
 * @return
 */
public float getMaxVal(){
    return maxVal;
}
Wechsle wieder zur GraphActivity und füge der Methode onCreate() den folgenden Code hinzu:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Bundle bundle = getIntent().getExtras();
setTitle(bundle.getString(MainActivity.EXTRA_TITLE));

location = bundle.getString(MainActivity.EXTRA_LOCATION);
devicetype = bundle.getString(MainActivity.EXTRA_DEVICETYPE);
id = bundle.getString(MainActivity.EXTRA_DEVICE);

//Graph definieren
lineChart = (LineChart) findViewById(R.id.linechart);
lineChart.setDescription(null);
lineChart.setHighlightPerDragEnabled(false);
lineChart.setScaleYEnabled(false);

dayList = new ArrayList<>();

Long now = System.currentTimeMillis();
Long then = now - ((long) (30 * dayMilliseconds)); //30 Tage zuvor

loadGraphData(formatter.format(then), formatter.format(now));
Da ein paar der benutzten Intent-Keys noch nicht existieren, und im Laufe dieses Tutorials noch weitere benötigt werden, öffnest du nun die Datei "MainActivity.java" und fügst die folgenden Intent-Keys zu den Attributen der MainActivity hinzu:
final static String EXTRA_DEVICETYPE = "EXTRA_DEVICETYPE";
final static String EXTRA_START_DATE = "EXTRA_START_DATE";
final static String EXTRA_END_DATE = "EXTRA_END_DATE";
final static String EXTRA_UNIT = "EXTRA_UNIT";
final static String EXTRA_DEVICE = "EXTRA_DEVICE";
final static String EXTRA_ID = "EXTRA_ID";
Außerdem fügst du vor allen Intent-Keys das Schlüsselwort "public" ein, damit die Intent-Keys auch in anderen Packages verfügbar sind. Wechsle wieder zur GraphActivity und füge unterhalb der onCreate()-Methode die folgenden drei überschriebenen Methoden ein:
@Override
public boolean onSupportNavigateUp() {
    super.onSupportNavigateUp();
    onBackPressed();
    getSupportFragmentManager().popBackStack();
    return true;
}

@Override
public boolean onCreateOptionsMenu(Menu menu){
    getMenuInflater().inflate(R.menu.activity_graph, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item){
    int post_id  = item.getItemId();

    if(post_id == R.id.change_period){
        Dialogs.chooseTimePeriodDialog(this, findViewById(R.id.frame), new Dialogs.OnPeriodChosenListener(){
            @Override
            public void onPeriodChosen(String start, String end){
                loadGraphData(start, end);
            }
        });
        return true;
    }

    return super.onOptionsItemSelected(item);
}
Die Methode onSupportNavigateUp() beendet die Activity, wenn der Zurück-Pfeil in der ActionBar geklickt wird. Mit den Methoden onCreateOptionsMenu() und onOptionsItemSelected() wird das Options-Menü erstellt, bzw. auf Menüpunkt-Klicks reagiert.

Dialoge erstellen

Als nächstes müssen die neuen Dialog-Methoden in der Klasse Dialogs implementiert werden. Öffne dazu die Klasse "Dialogs.java" im Package "system" und füge diese beiden Methoden und das Interface hinzu:
/**
 * Erstellt einen Dialog, um einen Zeitraum zu bestimmen
 * @param activity
 * @param view
 * @param periodChosenListener
 */
public static void chooseTimePeriodDialog(final Activity activity, final View view, final OnPeriodChosenListener periodChosenListener){
    final long dayMilliseconds = 60 * 60 * 24 * 1000;
    final DateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
    String[] items = {"Letzte 30 Tage", "Letzte 60 Tage", "Letzte 90 Tage",
            "Dieser Monat", "Letzter Monat", "Dieses Jahr", "Letztes Jahr", "Benutzerdefiniert"};

    AlertDialog.Builder builder = new AlertDialog.Builder(activity);

    builder.setTitle("Zeitraum w&auml;hlen");

    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Long now = System.currentTimeMillis();
            Long then;
            String vonDatum, bisDatum;
            int tag, monat, jahr;

            Calendar cal = Calendar.getInstance();

            switch(which){
                case 0:
                    then = now - ((long) 30 * dayMilliseconds);
                    periodChosenListener.onPeriodChosen(formatter.format((then)), formatter.format(now));
                    break;
                case 1:
                    then = now - ((long) 60 * dayMilliseconds);
                    periodChosenListener.onPeriodChosen(formatter.format((then)), formatter.format(now));
                    break;
                case 2:
                    then = now - ((long) 90 * dayMilliseconds);
                    periodChosenListener.onPeriodChosen(formatter.format((then)), formatter.format(now));
                    break;
                case 3:
                    tag = 31;
                    monat = cal.get(Calendar.MONTH);
                    jahr = cal.get(Calendar.YEAR);

                    switch (monat){
                        case Calendar.FEBRUARY:
                            if((jahr%4)==0){
                                tag = 29;
                            }
                            else tag = 28;
                            break;
                        case Calendar.APRIL:
                        case Calendar.JUNE:
                        case Calendar.SEPTEMBER:
                        case Calendar.NOVEMBER:
                            tag = 30;
                            break;
                    }

                    if(monat == Calendar.DECEMBER){
                        monat = Calendar.JANUARY;
                    }
                    else{
                        monat++;
                    }

                    vonDatum = "01." + monat + "." + jahr;
                    bisDatum = tag + "." + monat + "." + jahr;
                    periodChosenListener.onPeriodChosen(vonDatum, bisDatum);
                    break;
                case 4:
                    tag = 31;
                    monat = cal.get(Calendar.MONTH);
                    jahr = cal.get(Calendar.YEAR);

                    if(monat == Calendar.JANUARY){
                        monat = Calendar.DECEMBER;
                    }
                    else{
                        monat--;
                    }

                    switch (monat){
                        case Calendar.FEBRUARY:
                            if((jahr%4)==0){
                                tag = 29;
                            }
                            else tag = 28;
                            break;
                        case Calendar.APRIL:
                        case Calendar.JUNE:
                        case Calendar.SEPTEMBER:
                        case Calendar.NOVEMBER:
                            tag = 30;
                            break;
                    }

                    if(monat == Calendar.DECEMBER){
                        monat = Calendar.JANUARY;
                    }
                    else{
                        monat++;
                    }

                    vonDatum = "01." + monat + "." + jahr;
                    bisDatum = tag + "." + monat + "." + jahr;
                    periodChosenListener.onPeriodChosen(vonDatum, bisDatum);
                    break;
                case 5:
                    vonDatum = "01.01." + cal.get(Calendar.YEAR);
                    bisDatum = "31.12." + cal.get(Calendar.YEAR);
                    periodChosenListener.onPeriodChosen(vonDatum, bisDatum);
                    break;
                case 6:
                    jahr = cal.get(Calendar.YEAR)-1;

                    vonDatum = "01.01." + jahr;
                    bisDatum = "31.12." + jahr;
                    periodChosenListener.onPeriodChosen(vonDatum, bisDatum);
                    break;
                case 7:
                    Dialogs.chooseCustomTimePeriodDialog(activity, view, periodChosenListener);
                    break;
            }
        }
    });

    builder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });

    builder.show();
}

/**
 * Erstellt einen Dialog, um einen eigenen Zeitraum zu w&auml;hlen
 * @param activity
 * @param v
 * @param periodChosenListener
 */
public static void chooseCustomTimePeriodDialog(Activity activity, final View v,
                                                final OnPeriodChosenListener periodChosenListener){
    final Map<String, String> periodData = new HashMap<>();
    periodData.put("start", null);
    periodData.put("end", null);

    final Map<String, Long> periodTimestamps = new HashMap<>();
    periodTimestamps.put("start", null);
    periodTimestamps.put("end", null);

    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    builder.setTitle("Zeitraum w&auml;hlen");

    final View periodChooserView = activity.getLayoutInflater().inflate(R.layout.period_chooser, null);

    final DatePicker datePicker = (DatePicker) periodChooserView.findViewById(R.id.datepicker);

    final Button setStartDate = (Button) periodChooserView.findViewById(R.id.startDate);
    final Button setEndDate = (Button) periodChooserView.findViewById(R.id.endDate);

    builder.setView(periodChooserView);

    setStartDate.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int day = datePicker.getDayOfMonth();
            int month = datePicker.getMonth()+1;
            int year = datePicker.getYear();

            periodData.put("start", ((day<10)?("0"+day):day)+"."+((month<10)?("0"+month):month)+"."+year);

            Calendar calendar = new GregorianCalendar(year, month, day);
            periodTimestamps.put("start", calendar.getTimeInMillis());

            setStartDate.setText(periodData.get("start"));
        }
    });

    setEndDate.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int day = datePicker.getDayOfMonth();
            int month = datePicker.getMonth()+1;
            int year = datePicker.getYear();

            periodData.put("end", ((day<10)?("0"+day):day)+"."+((month<10)?("0"+month):month)+"."+year);

            Calendar calendar = new GregorianCalendar(year, month, day);
            periodTimestamps.put("end", calendar.getTimeInMillis());

            setStartDate.setText(periodData.get("end"));
        }
    });

    builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();

            if(periodData.get("start") == null || periodData.get("end") == null){
                Dialogs.fehlermeldung("Bitte lege ein Start- und ein Enddatum fest.", v);
            }
            else{
                if(periodTimestamps.get("start") < periodTimestamps.get("end")){
                    periodChosenListener.onPeriodChosen(periodData.get("start"), periodData.get("end"));
                }
                else{
                    Dialogs.fehlermeldung("Das Startdatum muss vor dem Enddatum liegen.", v);
                }
            }
        }
    });

    builder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });

    builder.show();

}

public interface OnPeriodChosenListener{
    /**
     * Wird aufgerufen, wenn ein Zeitraum ausgew&auml;hlt wurde
     * @param start
     * @param end
     */
    void onPeriodChosen(String start, String end);
}
Mit der Methode chooseTimePeriodDialog() wird ein Dialog dargestellt, der eine Liste an Optionen anzeigt. Diese Optionen sind zum Beispiel "Letzte 30 Tage", "Dieser Monat" oder "Letztes Jahr". Wird einer dieser Punkte gewählt, so wird die Methode onPeriodChosen() des Interfaces mit dem entsprechenden Zeitbereich aufgerufen. Außerdem gibt es einen Punkt "Benutzerdefinert". Wird er gewählt, so wird die Methode chooseCustomTimePeriodDialog() aufgerufen. Diese Methode stellt einen Dialog dar, in dem ein beliegbiges STart- und Enddatum ausgewählt werden kann. Anschließend wird die Methode onPeriodChosen() des Interfaces mit den entsprechenden Daten aufgerufen. Da die Methode chooseCustomTimePeriodDialog() das Layout "period_chooser.xml" verwendet, das noch nicht existiert, muss es nun erstellt werden. Klicke dazu mit rechts auf eine Layout-Datei und wähle "New -> Layout resource file". Gib ihr den Namen "period_chooser", gib als Root-Element "ScrollView" ein und klicke auf "Ok".
So wird die neue Layout-Datei erstellt.
Öffne nun das erstellte Layout und füge den folgenden Code in den ScrollView-Tag ein:
<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <DatePicker
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/datepicker"></DatePicker>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:text="Startdatum"
            style="@style/Base.Widget.AppCompat.Button.Colored"
            android:background="@color/colorPrimary"
            android:textColor="@color/textColorLight"
            android:textAllCaps="false"
            android:id="@+id/startDate"
            android:layout_weight="1"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:text="Enddatum"
            style="@style/Base.Widget.AppCompat.Button.Colored"
            android:background="@color/colorPrimary"
            android:textColor="@color/textColorLight"
            android:textAllCaps="false"
            android:id="@+id/endDate"
            android:layout_weight="1"/>

    </LinearLayout>

</LinearLayout>
Damit wird dem Layout ein DatePicker zur Datumsauswahl, sowie zwei Buttos, mit denen das ausgewählte Datum als Start- bzw. Enddatum des Zeitraums festgelegt werden kann, hinzugefügt.

GraphActivity fertig implementieren

Wechsle nun wieder zur Datei "GraphActivity.java" und füge die Methode loadGraphData() hinzu:
/**
 * L&auml;dt die Archivdaten des Sensors im angegebenen Bereich vom Server
 * @param vonDatum
 * @param bisDatum
 */
public void loadGraphData(String vonDatum, String bisDatum){
    lineChart.setVisibility(View.GONE);

    findViewById(R.id.empty_item).setVisibility(View.GONE);

    findViewById(R.id.loading_animation).setVisibility(View.VISIBLE);

    final Map<String, String> requestData = new HashMap<>();
    requestData.put("action", "getgraphdata");
    requestData.put("room", "location");
    requestData.put("type", devicetype);
    requestData.put("id", post_id);
    requestData.put("von", vonDatum);
    requestData.put("bis", bisDatum);

    requestData.put("username", SaveData.getUsername(getApplicationContext()));
    requestData.put("password", SaveData.getPassword(getApplicationContext()));

    HTTPRequest.sendRequest(getApplicationContext(), requestData, SaveData.getServerIp(getApplicationContext()), new HTTPRequest.HTTPRequestCallback() {
        @Override
        public void onRequestResult(String result) {
            findViewById(R.id.loading_animation).setVisibility(View.GONE);

            switch(result){
                default:
                    try{
                        JSONObject jsonObject = new JSONObject(result);

                        JSONArray values = jsonObject.getJSONArray("values");

                        einheit = jsonObject.getString("einheit");

                        dayList.clear();

                        for(int i = 0; i < values.length(); i++){
                            JSONObject o = values.getJSONObject(i);

                            dayList.add(new GraphDayItem(o.getString("date"), BigDecimal.valueOf(o.getDouble("min")).floatValue(),
                                    BigDecimal.valueOf(o.getDouble("max")).floatValue()));
                        }

                        fillLineChart();

                        if(dayList.isEmpty()){
                            lineChart.setVisibility(View.GONE);

                            findViewById(R.id.empty_item).setVisibility(View.VISIBLE);
                            ((ImageView) findViewById(R.id.empty_icon)).setImageResource(Icons.getDrawerIcon("overview"));
                            ((TextView) findViewById(R.id.empty_title)).setText("Keine Daten");
                            ((TextView) findViewById(R.id.empty_info)).setText("F&uuml;r den ausgew&auml;hlten Zeitraum sind keine Daten vorhanden.");
                        }

                    }
                    catch(JSONException e){
                        e.printStackTrace();

                        onError("");
                    }
                    break;
            }
        }

        @Override
        public void onError(String msg) {
            lineChart.setVisibility(View.GONE);

            findViewById(R.id.empty_item).setVisibility(View.VISIBLE);
            ((ImageView) findViewById(R.id.empty_icon)).setImageResource(Icons.getDrawerIcon("overview"));
            ((TextView) findViewById(R.id.empty_title)).setText("Keine Daten");
            ((TextView) findViewById(R.id.empty_info)).setText("Die Daten konnten nicht geladen werden");
        }
    });
}
Diese Methode hat die Parameter "vonDatum" und "bisDatum", die beide vom Typ String sind. Sie fragt mit einer HTTP-Request die vorhandenen Sensordaten dieses Sensors für den entsprechenden Zeitraum vom Server ab. Ist die Abfrage erfolgreich, so wird aus der Rückgabe des Servers in einem try-Block ein JSON-Objekt erstellt und daraus die Daten für den Werteverlauf und die Einheit des Sensors herausgelesen. Anschließend wird durch die Daten iteriert, für jedes Datum ein GraphDayItem erstellt und in die ArrayList "dayList" eingefügt. Anschließend wird die Methode fillLineChart() aufgerufen, die nachher implementiert wird. Ist die "dayList" leer, so wird der LineChart entfernt, das Empty-Item sichtbar gemacht und der Icon und die Texte entsprechend gesetzt. Falls im try-Block eine JSON-Exception geworfen wurde, so wird die Methode onError() des Interfaces mit einem leeren String aufgerufen. In der Methode onError() wird der LineChart entfernt, das Empty-Item sichtbar gemacht und Icon und Texte entsprechend gesetzt. Als letztes wird die Methode fillLineChart() implementiert. Füge sie unterhalb der Methode loadGraphData() ein:
/**
 * F&uuml;llt den LineChart mit Werten
 */
public void fillLineChart(){
    if(dayList.isEmpty()){
        return;
    }

    ArrayList<Entry> minVals = new ArrayList<>();
    ArrayList<Entry> maxVals = new ArrayList<>();

    final ArrayList<String> dates = new ArrayList<>();

    for(int i = 0; i < dayList.size(); i++){
        GraphDayItem item = dayList.get(i);

        minVals.add(new Entry(i, (float) item.getMinVal()));
        maxVals.add(new Entry(i, (float) item.getMaxVal()));

        dates.add(item.getDate());
    }

    //Einstellungen des Graphen
    final LineDataSet minLine = new LineDataSet(minVals, "Minumum");

    minLine.setMode(LineDataSet.Mode.CUBIC_BEZIER);
    minLine.setCubicIntensity(0.2f);

    minLine.setAxisDependency(YAxis.AxisDependency.LEFT);
    minLine.setColor(getResources().getColor(R.color.colorPrimary));
    minLine.setCircleSize(4.5f);
    minLine.setCircleColor(getResources().getColor(R.color.colorPrimary));
    minLine.setDrawCircles(true);
    minLine.setDrawValues(false);

    final LineDataSet maxLine = new LineDataSet(maxVals, "Maximum");

    maxLine.setMode(LineDataSet.Mode.CUBIC_BEZIER);
    maxLine.setCubicIntensity(0.2f);

    maxLine.setAxisDependency(YAxis.AxisDependency.LEFT);
    maxLine.setColor(getResources().getColor(R.color.red));
    maxLine.setCircleSize(4.5f);
    maxLine.setCircleColor(getResources().getColor(R.color.red));
    maxLine.setDrawCircles(true);
    maxLine.setDrawValues(false);

    ArrayList<ILineDataSet> dataSets = new ArrayList<>();
    dataSets.add(minLine);
    dataSets.add(maxLine);

    Legend legend = lineChart.getLegend();
    legend.setTextSize(20);

    LineData lineData = new LineData(dataSets);

    lineChart.animateY(500);
    lineChart.setData(lineData);

    XAxis xAxis = lineChart.getXAxis();
    xAxis.setGranularity(1f);
    xAxis.setValueFormatter(new IAxisValueFormatter() {
        @Override
        public String getFormattedValue(float value, AxisBase axis) {
            try{
                return dates.get((int) value);
            }
            catch(Exception e){
                e.printStackTrace();
                return String.valueOf(value);
            }
        }
    });

    lineChart.invalidate();
    lineChart.setVisibility(View.VISIBLE);
    lineChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
        @Override
        public void onValueSelected(Entry e, Highlight h) {
            int index = minLine.getEntryIndex(e);

            if(index == -1){
                index = maxLine.getEntryIndex(e);
            }

            if(index == -1){
                return;
            }

            //ValueCourseActivity starten
            /*Intent intent = new Intent(GraphActivity.this, ValueCourseActivity.class);
            intent.putExtra(MainActivity.EXTRA_START_DATE, dayList.get(index).getDate());
            intent.putExtra(MainActivity.EXTRA_DEVICETYPE, devicetype);
            intent.putExtra(MainActivity.EXTRA_ID, post_id);
            intent.putExtra(MainActivity.EXTRA_LOCATION, location);
            intent.putExtra(MainActivity.EXTRA_UNIT, einheit);
            startActivity(intent);*/
        }

        @Override
        public void onNothingSelected() {

        }
    });
}
Die Methode fillLineChart() setzt die Daten der "dayList" zu einem Liniendiagramm zusammen und stellt sie im LineChart dar. Außerdem wird dem LineChart ein Listener hinzugefügt, der eine Tagesübersicht aufruft, wenn ein Wert angeklickt wird. Dieser Aufruf wird jedoch auskommentiert, da die aufgerufene Activity erst im nächsten Tutorial erstellt und implementiert wird. Außerdem greift die Methode auf die Farben-Ressource "red" zu, die noch nicht existiert. Klicke auf den Aufruf der Farbe (bei mir in Zeile 221) und drücke Alt & die Eingabetaste. Wähle dann "Create color value resource 'red'". In diesem Fenster gibst du den Hex-Wert "#FF0000" ein und klickst auf "Ok".
Erstelle die neue Farben-Ressource.

GraphActivity aufrufen

Damit die GraphActivity nun auch gestartet wird, wenn ein Sensor angeklickt wird, muss die Methode showOverview() in der Klasse "RoomControl" implementiert werden. Öffne dazu die Datei "RoomControl.java" im Package "system". Füge dort den folgenden Code in den Rumpf der Methode showOverview() ein:
//GraphActivity aufrufen
Intent intent = new Intent(activity, GraphActivity.class);
intent.putExtra(MainActivity.EXTRA_TITLE, item.getName());
intent.putExtra(MainActivity.EXTRA_LOCATION, location);
intent.putExtra(MainActivity.EXTRA_DEVICETYPE, item.getDeviceType());
intent.putExtra(MainActivity.EXTRA_DEVICE, item.getId());
activity.startActivity(intent);
Mit diesem Code wird die GraphActivity aufgerufen und ihr die Daten des angeklickten Sensors übergeben, damit sie den Werteverlauf abfragen kann. Das war's schon wieder mit diesem Tutorial. Bei Fragen oder Problemen kannst du mir gerne einen Kommentar hinterlassen.

Über den Autor


Sascha Huber

Hallo, ich bin Sascha, der Gründer von Smarthome Blogger.

Mit einer Leidenschaft für Technologie und einem Hintergrund als Software Engineer habe ich 2016 Smarthome Blogger gegründet. Mein Ziel war es schon immer, innovative Lösungen zu entdecken, die unser Leben einfacher und intelligenter gestalten können. In meinem beruflichen Leben arbeite ich täglich mit Software und Technik, aber auch in meiner Freizeit bin ich stets auf der Suche nach neuen technischen Spielereien und Möglichkeiten, mein Zuhause zu automatisieren und zu verbessern.

Auf Smarthome Blogger teile ich mein Wissen, meine Erfahrungen und meine Begeisterung für alles rund um das Thema Smarthome.



Dieser Beitrag hat dir gefallen?

Dann abonniere doch unseren Newsletter!