title: Android/Java creating a helper class to create graphs
body: <p><strong>Goal:</strong></p>
  
  <p>To create a helper class for graph generation</p>
  
  <p><strong>Background:</strong></p>
  
  <p>I have 3 fragments that each collect some sensor data (accelerometer, gyroscope, rotation) and plots a graph using GraphView. Here is what the code looks like for one of those fragments (this code currently works correctly):</p>
  
  <pre><code>public class GyroscopeFragment extends Fragment implements SensorEventListener {
  
      private final short TYPE_GYROSCOPE = Sensor.TYPE_GYROSCOPE;
      private final short POLL_FREQUENCY = 100; //in milliseconds
      private final short MAX_POINTS_DISPLAYED = 50;
      private SensorManager sensorManager;
      private Sensor sensor;
      private Sensor gyroscope;
      private long lastUpdate = -1;
  
      float curGyroX;
      float curGyroY;
      float curGyroZ;
  
      private LineGraphSeries&lt;DataPoint&gt; gyroXSeries;
      private LineGraphSeries&lt;DataPoint&gt; gyroYSeries;
      private LineGraphSeries&lt;DataPoint&gt; gyroZSeries;
      private double graphXTime = 1d;
  
      public GyroscopeFragment() {
          // Required empty public constructor
      }
  
  
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
                               Bundle savedInstanceState) {
  
          // Inflate the layout for this fragment
          View view = inflater.inflate(R.layout.fragment_gyroscope, container, false);
  
          //Set the nav drawer item highlight
          MainActivity mainActivity = (MainActivity) getActivity();
          mainActivity.navigationView.setCheckedItem(R.id.nav_gyroscope);
  
          //Set actionbar title
          mainActivity.setTitle("Gyroscope");
  
          //Sensor manager
          sensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
          gyroscope = (Sensor) sensorManager.getDefaultSensor(TYPE_GYROSCOPE);
  
          return view;
      }
  
  
      @Override
      public void onResume() {
          super.onResume();
          sensorManager.registerListener(this, gyroscope, SensorManager.SENSOR_DELAY_FASTEST);
  
          //Create graph
          GraphView gyroGraph = (GraphView) getView().findViewById(R.id.gyroGraph);
  
          gyroGraph.getLegendRenderer().setVisible(true);
          gyroGraph.getLegendRenderer().setFixedPosition(0,0);
  
          gyroGraph.getGridLabelRenderer().setHighlightZeroLines(false);
  
          gyroXSeries = new LineGraphSeries&lt;DataPoint&gt;();
          gyroYSeries = new LineGraphSeries&lt;DataPoint&gt;();
          gyroZSeries = new LineGraphSeries&lt;DataPoint&gt;();
  
          gyroXSeries.setTitle("X");
          gyroYSeries.setTitle("Y");
          gyroZSeries.setTitle("Z");
  
          gyroXSeries.setColor(Color.RED);
          gyroYSeries.setColor(Color.GREEN);
          gyroZSeries.setColor(Color.BLUE);
  
          gyroGraph.addSeries(gyroXSeries);
          gyroGraph.addSeries(gyroYSeries);
          gyroGraph.addSeries(gyroZSeries);
  
          gyroGraph.getViewport().setYAxisBoundsManual(true);
          gyroGraph.getViewport().setMinY(-10);
          gyroGraph.getViewport().setMaxY(10);
  
          gyroGraph.getViewport().setXAxisBoundsManual(true);
          gyroGraph.getViewport().setMinX(0);
          gyroGraph.getViewport().setMaxX(MAX_POINTS_DISPLAYED);
      }
  
      @Override
      public void onPause() {
          super.onPause();
          sensorManager.unregisterListener(this);
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
          sensorManager.unregisterListener(this);
      }
  
      @Override
      public void onLowMemory() {
          super.onLowMemory();
          sensorManager.unregisterListener(this);
      }
  
      @Override
      public void onSensorChanged(SensorEvent event) {
          sensor = event.sensor;
  
          curGyroX = event.values[0];
          curGyroY = event.values[1];
          curGyroZ = event.values[2];
  
          long curTime = System.currentTimeMillis();
          long diffTime = (curTime - lastUpdate);
  
          // only allow one update every POLL_FREQUENCY.
          if (diffTime &gt; POLL_FREQUENCY) {
              lastUpdate = curTime;
  
              graphXTime += 1d;
              gyroXSeries.appendData(new DataPoint(graphXTime, curGyroX), true, MAX_POINTS_DISPLAYED);
              gyroYSeries.appendData(new DataPoint(graphXTime, curGyroY), true, MAX_POINTS_DISPLAYED);
              gyroZSeries.appendData(new DataPoint(graphXTime, curGyroZ), true, MAX_POINTS_DISPLAYED);
          }
      }
  
      @Override
      public void onAccuracyChanged(Sensor sensor, int accuracy) {
          //Safe not to implement
      }
  }
  </code></pre>
  
  <p>I find that across the 3 fragments I am repeating a lot of the graph generation code in <code>onResume</code> so I wanted to create a GraphHelper class that I can instantiate to do the graph creation, with the benefit of only having to change code in one place if I wanted to alter the look of a graph. However, I am new to Java so having trouble wrapping my head around creating this new class.</p>
  
  <p><strong>Attempted solution:</strong></p>
  
  <p>I have managed to come up with the following class in an attempt to solve the problem:</p>
  
  <pre><code>public class GraphHelper {
  
      private final GraphView graph;
      private final LineGraphSeries&lt;DataPoint&gt; xSeries;
      private final LineGraphSeries&lt;DataPoint&gt; ySeries;
      private final LineGraphSeries&lt;DataPoint&gt; zSeries;
  
      public GraphHelper(GraphView graph, LineGraphSeries&lt;DataPoint&gt; xSeries,
                              LineGraphSeries&lt;DataPoint&gt; ySeries, LineGraphSeries&lt;DataPoint&gt; zSeries, short maxDisplayed){
          this.graph = graph;
          this.xSeries = xSeries;
          this.ySeries = ySeries;
          this.zSeries = zSeries;
  
          graph.getLegendRenderer().setVisible(true);
          graph.getLegendRenderer().setFixedPosition(0, 0);
  
          graph.getGridLabelRenderer().setHighlightZeroLines(false);
  
          xSeries = new LineGraphSeries&lt;DataPoint&gt;();
          ySeries = new LineGraphSeries&lt;DataPoint&gt;();
          zSeries = new LineGraphSeries&lt;DataPoint&gt;();
  
          xSeries.setTitle("X");
          ySeries.setTitle("Y");
          zSeries.setTitle("Z");
  
          xSeries.setColor(Color.RED);
          ySeries.setColor(Color.GREEN);
          zSeries.setColor(Color.BLUE);
  
          graph.addSeries(xSeries);
          graph.addSeries(ySeries);
          graph.addSeries(zSeries);
  
          graph.getViewport().setYAxisBoundsManual(true);
          graph.getViewport().setMinY(-10);
          graph.getViewport().setMaxY(10);
  
          graph.getViewport().setXAxisBoundsManual(true);
          graph.getViewport().setMinX(0);
          graph.getViewport().setMaxX(maxDisplayed);
      }
  }
  </code></pre>
  
  <p>And have changed my fragment <code>onResume</code> to look like this (everything else is the same):</p>
  
  <pre><code>@Override
  public void onResume() {
      super.onResume();
      sensorManager.registerListener(this, gyroscope, SensorManager.SENSOR_DELAY_FASTEST);
  
      //Create graph
      GraphView gyroGraph = (GraphView) getView().findViewById(R.id.gyroGraph);
  
      new GraphHelper(gyroGraph, gyroXSeries, gyroYSeries, gyroZSeries, MAX_POINTS_DISPLAYED);
  }
  </code></pre>
  
  <p><strong>Problem #1:</strong></p>
  
  <p>I am getting the following error whenever I try to view the graph fragment:</p>
  
  <pre><code>java.lang.NullPointerException: Attempt to invoke virtual method 'void com.jjoe64.graphview.series.LineGraphSeries.appendData(com.jjoe64.graphview.series.DataPointInterface, boolean, int)' on a null object reference
  </code></pre>
  
  <p>This is referring to the <code>onSensorChanged</code> method where I'm trying to append data to the series. It doesn't seem to know what <code>gyroXSeries</code> is because I'm adding it to the graph within the helper.</p>
  
  <p><strong>Problem #2:</strong></p>
  
  <p>Currently I'm declaring <code>gyroXSeries</code> in the main fragment class, as well as the top of the helper class, and also creating a new <code>LineGraphSeries</code> object in the helpers constructor. Is there a way to reduce the repetition of this code?</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>In response to the comments below, I made the following changes and the new GraphHelper class looks like this:</p>
  
  <pre><code>public class GraphHelper {
  
      private final GraphView graph;
      private final LineGraphSeries&lt;DataPoint&gt; xSeries;
      private final LineGraphSeries&lt;DataPoint&gt; ySeries;
      private final LineGraphSeries&lt;DataPoint&gt; zSeries;
  
  
      public GraphHelper(GraphView graph, LineGraphSeries&lt;DataPoint&gt; xSeries,
                              LineGraphSeries&lt;DataPoint&gt; ySeries, LineGraphSeries&lt;DataPoint&gt; zSeries, short maxDisplayed){
          this.graph = graph;
          this.xSeries = xSeries;
          this.ySeries = ySeries;
          this.zSeries = zSeries;
  
          graph.getLegendRenderer().setVisible(true);
          graph.getLegendRenderer().setFixedPosition(0, 0);
  
          graph.getGridLabelRenderer().setHighlightZeroLines(false);
  
          xSeries.setTitle("X");
          ySeries.setTitle("Y");
          zSeries.setTitle("Z");
  
          xSeries.setColor(Color.RED);
          ySeries.setColor(Color.GREEN);
          zSeries.setColor(Color.BLUE);
  
          graph.addSeries(xSeries);
          graph.addSeries(ySeries);
          graph.addSeries(zSeries);
  
          graph.getViewport().setYAxisBoundsManual(true);
          graph.getViewport().setMinY(-10);
          graph.getViewport().setMaxY(10);
  
          graph.getViewport().setXAxisBoundsManual(true);
          graph.getViewport().setMinX(0);
          graph.getViewport().setMaxX(maxDisplayed);
      }
  }
  </code></pre>
  
  <p>The gyroscope fragment is the same as the original, with the change to <code>onResume</code> that I made above</p>
  
  <p>Which results in the following error:</p>
  
  <p>FATAL EXCEPTION: main
                                                                            Process: net.binarysea.sensorload, PID: 25997
                                                                            java.lang.NullPointerException: Attempt to invoke virtual method 'void com.jjoe64.graphview.series.LineGraphSeries.setTitle(java.lang.String)' on a null object reference
                                                                                at net.binarysea.sensorload.GraphHelper.(GraphHelper.java:30)
                                                                                at net.binarysea.sensorload.GyroscopeFragment.onResume(GyroscopeFragment.java:73)
                                                                                at android.support.v4.app.Fragment.performResume(Fragment.java:2005)
                                                                                at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1108)
                                                                                at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
                                                                                at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
                                                                                at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
                                                                                at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:517)
                                                                                at android.os.Handler.handleCallback(Handler.java:739)
                                                                                at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                at android.os.Looper.loop(Looper.java:148)
                                                                                at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)</p>