halfhp / androidplot

Charts and plots for Android
http://androidplot.com
Apache License 2.0
505 stars 159 forks source link

SampledXYSeries crashes the app on attempt to read .csv file #91

Closed vasyl91 closed 5 years ago

vasyl91 commented 5 years ago

I wrote snippet that reads simple .csv file:

import java.util.List;
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.time.DurationFormatUtils;
import org.apache.commons.io.comparator.LastModifiedFileComparator;
import org.apache.commons.io.filefilter.WildcardFileFilter;

...

public int graphNumber = 0; // <--- HERE

...

    private void generateSeriesData() {
        new AsyncTask() {

            @Override
            protected Object doInBackground(Object[] objects) {
                Double[] pointsY = generatePoints();
                generateAndAddSeries(pointsY);
                return null;
            }

            @Override
            protected void onPostExecute(Object result) {
                csvPlot.redraw();
            }
        }.execute();
    }

    private Double[] generatePoints() {
        Double[] points = null;
        String directoryString = "/storage/emulated/0/project/";
        File directory = new File(directoryString);
        if (getFilesCount(directory) > 0) {
            FileFilter fileFilter = new WildcardFileFilter("*.csv");
            File[] files = directory.listFiles(fileFilter);
            Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
            String stringFile = directoryString + files[graphNumber].getName();  // <--- HERE
            File file = new File(stringFile);
            if (file.length() > 0) {
                List<String[]> data = new ArrayList<>();
                String[] content = null;
                CsvParserSettings settings = new CsvParserSettings();
                CsvParser parser = new CsvParser(settings);
                String[] rows;
                parser.beginParsing(file);
                String[] firstRow = parser.parseNext();
                while ((rows = parser.parseNext()) != null) {
                    String lastRow = rows[0];
                    content = rows;
                    data.add(content);
                    points = new Double[data.size()];
                    for (int i = 0; i < data.size(); i++){
                        rows = data.get(i);
                        points[i] = new Double(Double.parseDouble(rows[1]));                      
                    }
                    csvPlot.getOuterLimits().set(0, 100, 0, Double.parseDouble(lastRow));      
                }
            } 
        }
        return points;        
    }

    private void generateAndAddSeries(Double[] pointsY) {
        XYSeries dataSeries = new SimpleXYSeries(Arrays.asList(pointsY), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Series1");       
        SampledXYSeries sampledSeries = new SampledXYSeries(dataSeries, OrderedXYSeries.XOrder.ASCENDING, 2,10);
        PixelUtils.init(getContext());
        lineFormatter = new FastLineAndPointRenderer.Formatter(LINE_COLOUR, null,  null);
        lineFormatter.getLinePaint().setStrokeWidth(6);
        csvPlot.addSeries(sampledSeries, lineFormatter);   
    }

Catalogue /storage/emulated/0/ProjectName/ contains .csv files. By changing graphNumber user chooses which file to read. 0 is the newest, 1 is the second one and so on.

If graphNumber (arrows in the code above) is immutable, everything works perfect. But when I try to set it with function (then it becomes not immutable), app loads series and almost instantly crashes.

I tried to catch this error with LogCat, it returns:

02-01 22:55:16.926 10881 10932 E AndroidRuntime: Process: com.project, PID: 10881
02-01 22:55:16.926 10881 10932 E AndroidRuntime:        at com.project.components.graphs.CSVGraph.generateAndAddSeries(CSVGraph.java:259)
02-01 22:55:16.926 10881 10932 E AndroidRuntime:        at com.project.components.graphs.CSVGraph.access$100(CSVGraph.java:85)
02-01 22:55:16.926 10881 10932 E AndroidRuntime:        at com.project.components.graphs.CSVGraph$1.doInBackground(CSVGraph.java:189)
02-01 22:55:16.928  1684  2447 W ActivityManager:   Force finishing activity com.project/.MainActivity
02-01 22:55:17.075  1684  2445 I WindowState: WIN DEATH: Window{9c925fe u0 com.project/com.project.MainActivity}

To reproduce this issue copy/paste provided code, create random .csv file (mine contains two columns with numbers) and call generateSeriesData(). NOTE: this snipped uses Univocity so you'll have to add this: implementation group: 'com.univocity', name: 'univocity-parsers', version: '2.7.6' to your dependencies.

vasyl91 commented 5 years ago

That was the most ridiculous error that occured to me to unravel. It turned out that this part of code checks every file in provided catalogue and if it is empty - throws an error, even though this file was not called. This snippet inside initView() method that sets graphNumber does the trick:

        FileFilter fileFilter = new WildcardFileFilter("*.csv");
        File[] files = directory.listFiles(fileFilter);
        Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
        String stringFile = directoryString + files[number].getName();
        try {
            BufferedReader br = new BufferedReader(new FileReader(stringFile)); 
            if (br.readLine() != null) {
                graphNumber = number;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

Problem was probably related to the fact that I'm using react-native. Closing issue.

halfhp commented 5 years ago

Hey sorry I just now saw this (been out of reach of a computer for the weekend). Glad you were able to resolve it!