7

I'm a beginner in Android so forgive me if this is a super easy fix. I've looked at other posts on here in regard to the same NullPointerException matter, however I still cannot find the source of the error in my code.

I have a very simple project that has Main java class and a fragment class. When a user clicks a radio button the background color of the main activity must change but I keep getting:

java.lang.NullPointerException: Attempt to invoke interface method 'OnColorChangeListener.colorChanged(java.lang.String)' on a null object reference.

Activity5.java:

public class Activity5 extends AppCompatActivity implements ColorFragment.OnColorChangeListener {

    LinearLayout linearLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_5);
        linearLayout = (LinearLayout)findViewById(R.id.main_layout_id);
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        ColorFragment colorFragment = new ColorFragment();
        fragmentTransaction.add(R.id.fragment_container, colorFragment);
        fragmentTransaction.commit();
    }

    @Override
    public void colorChanged(String colorname) {
        if(colorname.equals("RED")) {
            linearLayout.setBackgroundColor(Color.RED);
        }
        else if(colorname.equals("GREEN")) {
            linearLayout.setBackgroundColor(Color.GREEN);
        }
        else if(colorname.equals("BLUE")){
            linearLayout.setBackgroundColor(Color.BLUE);
        }

        else if(colorname.equals("MAGENTA")) {
            linearLayout.setBackgroundColor(0xffff00ff);
        }
        else if(colorname.equals("YELLOW")) {
            linearLayout.setBackgroundColor(0xffffff00);
        }

    }
} 

Now here's the Fragment Class:

public class ColorFragment extends Fragment {

    OnColorChangeListener onColorChangeListener;


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

        RadioGroup radioButtonGroup = (RadioGroup)view.findViewById(R.id.color_radio_group);
        radioButtonGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){
            @Override
            public void onCheckedChanged(RadioGroup group, int checkIdOfButton) {

                switch (checkIdOfButton){
                    case R.id.red_id:
                        onColorChangeListener.colorChanged("RED");
                        break;
                    case R.id.green_id:
                        onColorChangeListener.colorChanged("GREEN");
                        break;
                    case R.id.blue_id:
                        onColorChangeListener.colorChanged("BLUE");
                        break;
                    case R.id.magenta_id:
                        onColorChangeListener.colorChanged("MAGENTA");
                        break;
                    case R.id.yellow_id:
                        onColorChangeListener.colorChanged("YELLOW");
                        break;
                }
            }
        });

        return view;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        try {
            onColorChangeListener = (OnColorChangeListener) context;
        }
        catch catch (Exception e){}
        }
    }
    public interface OnColorChangeListener
    {
        public void colorChanged(String colorname);
    }
}

Here is the XML Activity:

<LinearLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.user.seriousapp.Activity5"
    tools:showIn="@layout/activity_5"
    android:id="@+id/main_layout_id">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Fragment Communication Example"
        android:id="@+id/textView2"
        android:textColor="#000000"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:id="@+id/fragment_container"
        android:layout_marginTop="60dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:gravity="center"></RelativeLayout>

</LinearLayout>

And finally here is the XML Fragment:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="250dp"
    android:background="#000000">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Select a Color"
        android:textColor="#ffffff"
        android:id="@+id/textView3"
        android:layout_gravity="center_horizontal" />

    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        android:orientation="vertical"
        android:id="@+id/color_radio_group">

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="RED"
            android:textColor="#ffffff"
            android:buttonTint="#ffffff"
            android:id="@+id/red_id" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="GREEN"
            android:textColor="#ffffff"
            android:buttonTint="#ffffff"
            android:id="@+id/green_id" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="BLUE"
            android:textColor="#ffffff"
            android:buttonTint="#ffffff"
            android:id="@+id/blue_id" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="MAGENTA"
            android:textColor="#ffffff"
            android:buttonTint="#ffffff"
            android:id="@+id/magenta_id" />

        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="YELLOW"
            android:textColor="#ffffff"
            android:buttonTint="#ffffff"
            android:id="@+id/yellow_id" />

    </RadioGroup>
</LinearLayout>
Pang
  • 9,564
  • 146
  • 81
  • 122
user2590243
  • 83
  • 1
  • 1
  • 3
  • A quick once over actually looks good. What happens if you remove the `try...catch` statement in your `onAttach` method in the fragment or print something to logcat in the catch? I just want to make sure the context in the `onAttach` method really implements the `OnColorChangeListener` interface. – George Mulligan Jan 18 '16 at 03:23
  • I removed the try..catch like this but it didn't work, when i click any radio button i get: "Unfortunately SeriousApp has stopped": public void onAttach(Context context) { super.onAttach(context); onColorChangeListener = (OnColorChangeListener) context; } How would i go about printing something to the logcat in catch? – user2590243 Jan 18 '16 at 03:29
  • One last test sorry I should have just said this in the first place. Try printing something from inside the `onAttach` method to Logcat to see if the method is really being called. `Log.e("ColorFragment", "Inside onAttach");` – George Mulligan Jan 18 '16 at 03:33
  • It did not write anything to the logcat, which I guess means that the method isn't being called. – user2590243 Jan 18 '16 at 03:43
  • Right see my answer. Your device likely isn't API level 23 which is when the new onAttach method was added. – George Mulligan Jan 18 '16 at 03:44
  • Wow that worked, thank you so much! Another quick question, I used the onAttach() method on this same device with other projects and it worked just fine (overriding the method). How is it possible that it worked for one project and not this one on same device? – user2590243 Jan 18 '16 at 03:52
  • My best guess is the other projects were using `onAttach(Activity activity)` and not the newer version that takes a `Context`. You can also check the `targetSdkVersion` in your build file in the other projects. If it is under 23 there is no chance to use the new method that takes a `Context`. Another thought is maybe you are using the support library in your other projects and supposedly it works correctly by calling `onAttach(Context context)` even on devices under API 23. – George Mulligan Jan 18 '16 at 03:56

2 Answers2

6

Chances are you need to override the overloaded version onAttach(Activity activity) in the fragment as the other one that takes a Context is not being called. This is most likely because your Android device is not API 23+ and the version of the method you are using was added in API 23.

@Override
public void onAttach(Activity activity) {
    super.onAttach(context);

    try {
        onColorChangeListener = (OnColorChangeListener) context;
    }
    catch catch (Exception e){
        // you should really do something here with this exception
    }
}

EDIT

Alternatively switch to using the support library that includes the support fragment manager and fragments.

That should correctly call onAttach(Context context) even on pre API 23 devices.

George Mulligan
  • 11,813
  • 6
  • 37
  • 50
  • Thank you very much this worked. My only remaining question is how is it that I've overriden the onAttach(context) method on other projects and it's worked on this device which is the same one i'm currently using for this project? – user2590243 Jan 18 '16 at 04:00
  • Look at my second to last [comment](http://stackoverflow.com/questions/34846717/java-lang-nullpointerexception-attempt-to-invoke-interface-method-oncolorchang/34846934#comment57434308_34846717) under your question. I gave some guesses there. One of them should be the reason. – George Mulligan Jan 18 '16 at 04:02
  • Of course, trying to figure out how to do so. – user2590243 Jan 18 '16 at 04:13
2

Try initializing the listener in onCreate() or onActivityCreated() method using getActivity()

onColorChangeListener = (OnColorChangeListener) getActivity();
diedu
  • 19,277
  • 4
  • 32
  • 49