I've created a line chart in a fragment on android studio using MPandroidchart, and made it so that the points of the chart are from user input. However, I get the error 'java.lang.NullPointerException'. I understand that this error is caused by attempting to use a value that is null, but I'm not sure how to fix it in my case.
EDIT: the user input is saved in a room database
I retrieve the user input from a method where there is code to ensure that the input is not saved if it is null. I believe the issue is because the graph is attempting to build before the user can add the data, as the input option is part of the fragment where the graph is displayed, so the graph is trying to build before the data is ready.
Graph.java
public class Graph extends Fragment {
public Graph() {
// Required empty public constructor
}
private LineChart mChart;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_graph, container, false);
//initialize input1 database
InputRoomDatabase db = Room.databaseBuilder(getActivity(),InputRoomDatabase.class, "input_database")
.build();
//initialize chart
mChart = view.findViewById(R.id.chart);
//set description
Description description = new Description();
description.setText("Blood glucose levels");
mChart.setDescription(description);
//set description if no data is available
mChart.setNoDataText("No Data Available. Add a blood glucose level input to see your graph");
//enable touch gestures
mChart.setTouchEnabled(true);
//enable scaling and dragging
mChart.setDragEnabled(true);
mChart.setScaleEnabled(true);
//draw background grid
mChart.setDrawGridBackground(true);
//draw x-axis
XAxis xAxis = mChart.getXAxis();
xAxis.setEnabled(false);
// setting position to TOP and INSIDE the chart
xAxis.setPosition(XAxis.XAxisPosition.TOP_INSIDE);
// setting text size for our axis label
xAxis.setTextSize(10f);
xAxis.setTextColor(Color.BLACK);
// to draw axis line
xAxis.setDrawAxisLine(true);
xAxis.setDrawGridLines(false);
YAxis yAxis = mChart.getAxisLeft();
// setting the count of Y-axis label's
yAxis.setLabelCount(12, false);
yAxis.setTextColor(Color.BLACK);
yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
yAxis.setDrawGridLines(true);
mChart.getAxisRight().setEnabled(false);
// add data
setData();
mChart.getLegend().setEnabled(false);
// refresh the chart
mChart.notifyDataSetChanged();
mChart.invalidate();
return view;
}
private void setData(){
ArrayList<Entry> values = new ArrayList<>();
**
Double d = getActivity().getIntent().getExtras().getDouble("STRING_I_NEED");
**
float myDataSet = d.floatValue();
values.add(new Entry(1,myDataSet));
LineDataSet set1;
if (mChart.getData() != null &&
mChart.getData().getDataSetCount() > 0) {
set1 = (LineDataSet) mChart.getData().getDataSetByIndex(0);
set1.setValues(values);
mChart.getData().notifyDataChanged();
mChart.notifyDataSetChanged();
} else {
set1 = new LineDataSet(values, "Blood Glucose Levels");
set1.setDrawIcons(false);
set1.setLineWidth(2f);
set1.setCircleRadius(3f);
set1.setDrawCircleHole(false);
set1.setValueTextSize(9f);
set1.setFormLineWidth(1f);
set1.setFormSize(15.f);
set1.setColor(Color.BLACK);
set1.setCircleColor(Color.BLACK);
}
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);
LineData data = new LineData(dataSets);
mChart.setData(data);
}
}
Tabbed.java (base class of the fragment) (relevant code only)
//getting inputs from room and putting them into the view in table
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mInputViewModel = ViewModelProviders.of(this).get(InputViewModel.class);
//only add if there is a new input
if (requestCode == INPUT_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
//retrieve input from room database
Input1 input1 = new Input1(data.getStringExtra(input.EXTRA_REPLY));
//insert the inputs into the view model of the recyclerView
mInputViewModel.insert(input1);
//convert the String input1 to a double
Double d = Double.parseDouble(input1.getValue());
//display pop-up if blood is above target
if (d > 8.0) {
Toast.makeText(
getApplicationContext(),
R.string.PopupHigh,
Toast.LENGTH_LONG).show();
}
//display pop-up if blood is below target
if (d < 4.0) {
Toast.makeText(
getApplicationContext(),
R.string.PopupLow,
Toast.LENGTH_LONG).show();
}
Intent i = new Intent(Tabbed.this, Graph.class);
i.putExtra("STRING_I_NEED", d);
//display pop-up if no input is added don't save the input
} else {
Toast.makeText(
getApplicationContext(),
R.string.empty_not_saved,
Toast.LENGTH_LONG).show();
}
}
public static final int INPUT_ACTIVITY_REQUEST_CODE = 1;
}
When I run the app, it crashes and gives this error java.lang.NullPointerException: Attempt to invoke virtual method 'double android.os.Bundle.getDouble(java.lang.String)' on a null object reference
I've marked the problem code in Graph.java with **
As I said, I believe the issue is that the graph is trying to build before the data is ready, but I'm not sure how to avoid this issue.
Thanks for the help!
The code:
Double d = getActivity().getIntent().getExtras().getDouble("STRING_I_NEED");
float myDataSet = d.floatValue();
assumes 4 method calls all return non-null values. Please see the documentation for library methods to find out when they might return null
, and in general how to avoid unhappy surprises.
The documentation says getExtras() returns
the map of all extras previously added with putExtra(), or null if none have been added.
When calling a library method that can return null
, your code should check for the null
result (or catch the NullPointerException
), or ensure that that case can't happen, or both.
Intents
come in from the rest of the system, you can't guarantee that they will always have extras, so the code will need to test if the result of getExtras()
is null
before calling getDouble()
, and handle that gracefully. Intent
has no extras when you expected that it would. Intent
has extras but those extras don't have a double value called "STRING_I_NEED"
, then getDouble("STRING_I_NEED")
will return 0.0
. You might need to pass an explicit defaultValue
to getDouble()
or test if the Bundle
containsKey("STRING_I_NEED")
. getFloat()
instead of getDouble()
. I think that will convert a double value to float for you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.