JS302 JS302 - 4 months ago 45
Android Question

Null Pointer Exception inside a Fragment

I am trying to update a

View
, which represents a
graph(MpAndroidChart=library, class=BarChart)
, that is inside a
Fragment
based on input returned from a rest call. I try to update the View by using a method called
updateGraph()
, and I am getting a null pointer exception.

The code for my
updateGraph()
method is as below.

Any help for this would be greatly appreciated.

A general explanation of how this method is being called is as follows: My
MainActivity
creates a runnable which calls
updateGraph()
on an instance of
FragmentOne
that I create and use as a field in my
Activity
.

I then pass that runnable to my
RestCall(AsyncTask)
so to avoid passing the activity itself.

When the information from the rest call is returned, I save it into a singleton and reference it, similar to what you would do in
SharedPreferences
, to update the graph.

The code below uses predefined values to update the graph and does not worry about referencing the information just described as I am simply trying to get the graph to update at this moment.

public class FragmentOne extends Fragment implements Summary {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}

@Override
public void updateGraph() {
BarChart theChart = (BarChart) this.getView().findViewById(R.id.chart_frag_one);
ArrayList<BarEntry> entries = new ArrayList<>();
List<TupleFloat> prices = new ArrayList<TupleFloat>();
prices.add(new TupleFloat(2,4));
prices.add(new TupleFloat(3,4));
prices.add(new TupleFloat(1,6));
prices.add(new TupleFloat(3,1));
prices.add(new TupleFloat(1,1));
prices.add(new TupleFloat(7,2));
prices.add(new TupleFloat(3,2));

int prices_length = prices.size(); // need to delete

for (int i = 1; i < prices_length+1; i++){
entries.add(new BarEntry( (float) (i*2), new float[] {prices.get(i-1).getX(), prices.get(i-1).getY()}));
}


BarDataSet dataset = new BarDataSet(entries, " Summary"); // asbtract Summary
String datas[] = {"regular", "peak"};
dataset.setStackLabels(datas);
dataset.setColors(new int[] {R.color.portal_dark_blue, R.color.portal_light_blue}, getActivity());


YAxis left = theChart.getAxisLeft();
left.setAxisMaxValue(10);//dataset.getYMax()+2);
left.setAxisMinValue(0);
theChart.getAxisRight().setEnabled(false);
XAxis bottomAxis = theChart.getXAxis();
bottomAxis.setPosition(XAxis.XAxisPosition.BOTTOM);

bottomAxis.setValueFormatter(new AxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {

// return values will all be the values of the dates array
int value_i = (int) value;
Log.d("hello", Integer.toString(value_i));

switch(value_i){
case 2:
return "Jul 27";
case 4:
return "Jul 28";
case 6:
return "Jul 29";
case 8:
return "Jul 30";
case 10:
return "Jul 31";
case 12:
return "Aug 1";
case 14:
return "Aug 2";
}
return "";
}

@Override
public int getDecimalDigits() {
return 0;
}
});

bottomAxis.setAxisMinValue(0);
bottomAxis.setLabelCount(16); // size of array * 2 + 1
bottomAxis.setAxisMaxValue(dataset.getXMax()+3); // going to be dates-array based
bottomAxis.setDrawGridLines(false);
theChart.setDrawValueAboveBar(false);
theChart.setDescription("");

BarData data = new BarData(dataset);
theChart.setData(data);

// legend
Legend legend = theChart.getLegend();
legend.setYOffset(40);
legend.setPosition(Legend.LegendPosition.BELOW_CHART_CENTER);
legend.setTextSize(200);
}
}


Stack trace:

08-09 12:59:27.312 27094-27094/com.example.schadtj.portalapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.schadtj.portalapp, PID: 27094
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
at com.example.schadtj.portalapp.FragmentOne.updateGraph(FragmentOne.java:38)
at com.example.schadtj.portalapp.MainActivity$1.run(MainActivity.java:36)
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)


Fragment_one xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fvone"
>


<LinearLayout
android:id="@+id/tobegraph"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">


<com.github.mikephil.charting.charts.BarChart
android:id="@+id/chart_frag_one"
style="@style/AppTheme"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android" />

</LinearLayout>

</LinearLayout>


MainActivity necessary code

public class MainActivity extends Activity{
FragmentManager FM = getFragmentManager();
private BottomBar mBottomBar;
FragmentOne frag1;


@Override
public void onCreate(Bundle savedInstanceState) {
// Map of Runnables
Map<String, Runnable> rest_runnables = new HashMap<String, Runnable>();
frag1 = new FragmentOne();
Runnable summary = new Runnable() {
@Override
public void run() {
frag1.updateGraph();
}
};
rest_runnables.put("Summary", summary);
new RestUpdateAll(this, ((MyApplication) this.getApplication()).returnUser(), rest_runnables).execute();

Answer

Don't call updateGraph from the Activity like this (see your run method). The Fragment has no View at that point, so getView will return null, as seen in your error.

FragmentOne f = new FragmentOne();
f.updateGraph(); // This is bad... Will throw error

// fragment transaction ...

Instead, you can update the graph of the Fragment when the Fragment is loaded. Your "runnable" should be attached to the Fragment in some way if you are looking to periodically refresh this view.

public class FragmentOne extends Fragment implements Summary {

    private BarChart theChart;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View view = inflater.inflate(R.layout.fragment_one, container, false);
        theChart = (BarChart) view.findViewById(R.id.chart_frag_one);
        // Any other findViewById...

        return view;
    }

    @Override
    public void updateGraph() {

        ArrayList<BarEntry> entries = new ArrayList<>();
        List<TupleFloat> prices = new ArrayList<TupleFloat>();
        prices.add(new TupleFloat(2,4));
        ...