1

Not sure what's wrong with my observer pattern:

I have defined my interface as:

public interface OnBackFilterPressListener {
    public ArrayList<FoodType> filterFoodType ();
}

When I press the back button, I want the listener to be activated - all this code is in my activity class:

        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    onBackFilterPressListener.filterFoodType();
}
}

In my adapter class, I have the following code:

public class RandomRecyclerViewAdapter  extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements SearchActivity.OnBackFilterPressListener {

       @Override
    public ArrayList<FoodType> filterFoodType() {
        return foodTypes;
    }

}

When I press the back button in my activity, I just want the array of data in my adapter to be returned in my activity class.

But I'm getting this error:

java.lang.NullPointerException: Attempt to invoke interface method 'java.util.ArrayList com.example.simon..SearchActivity$OnBackFilterPressListener.filterFoodType()' on a null object reference

foodType definitely exists - the adapter loads the data into activity and I can see it being displayed on the android emulator. I get this error when I click the back button.

Simon
  • 19,658
  • 27
  • 149
  • 217
  • Apparently `onBackFilterPressListener` is `null`. How did you initialize it? – Stan Oct 14 '15 at 17:31
  • Maybe thats the problem... I just said OnBackFilterPressListener onBackFilterPressListener as my member variable. How should I have initialize it? – Simon Oct 14 '15 at 17:33
  • Assign your instance of `RandomRecyclerViewAdapter` to it. – Stan Oct 14 '15 at 17:44
  • @Simon SearchActivity is a Activity class right? Where is the recyclerview attached to?. Is it for a different activity? – Raghunandan Oct 14 '15 at 17:49
  • So SearchActivity is an activity class that holds a reference to a fragment. Inside the fragment is a recyclerview and the adapter is for that recyclerview. It really doesn't matter though as surely the observer pattern will observe it anywhere you place it and will be triggered once your event occurs? The activity, fragment and adapter are all displayed at once on the screen at the same time, so its not like there are within activity or fragment that are onStop or onPaused. – Simon Oct 14 '15 at 17:52
  • @Stan, but my RandomRecyclerViewAdapter already implements it and I have already made it implement the abstract filterFoodType() method from the adapter. – Simon Oct 14 '15 at 17:54
  • @Simon onBackFilterPressListener =(OnBackFilterPressListener) your instance of RandomRecyclerViewAdapter . You could use a EventBus. You could also take a look @ Rx Java but it needs a bit of time to get around. – Raghunandan Oct 14 '15 at 17:55
  • I thought about an eventBus but then I wonder if it would be wise to use it within an adapter class as you are not really following the activity/fragment lifecycle if you use it there. You cannot stop the eventBus inside an adapter. I might have to use one as the back button is in the activity class and the recyclerview is in the fragment so I cannot cast the recyclerview to onBackFilterPressListener as I want it to be called when the back button, which is in the activity class, is pressed. – Simon Oct 14 '15 at 18:02

1 Answers1

1

I got it to work by following this thread and being a little creative:

How to create our own Listener interface in android?

I wrote a custom object to prevent the null object reference as to use the interface, I would first have to create the object:

public class BackFilterEvent implements Serializable {

    private OnEventListener mOnEventListener;

    public void setOnEventListener(OnEventListener listener) {
        mOnEventListener = listener;
    }

    public ArrayList<FoodType> doEvent() {
        if (mOnEventListener != null) {
            return mOnEventListener.onEvent(); 
        }
        return null;
    }

    public interface OnEventListener {
        ArrayList<FoodType> onEvent();
    }

}

Then in my Activity class, I created the object:

BackFilterEvent backFilterEvent = new BackFilterEvent();

And I pass it as far as it needs to go in my code. In my case, I had an activity that feed a fragment with an recyclerview adapter within the fragment. I passed this object until it got to the recyclerview adapter.

Passing object from Activity to Fragment:

            FilterSearchFragment filterSearchFragment = new FilterSearchFragment();
            Bundle bundle = new Bundle();
            bundle.putSerializable("listener", backFilterEvent);
            filterSearchFragment.setArguments(bundle);
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, filterSearchFragment)
                    .commit();

Passing from Fragment to Adapter:

    Bundle bundle = getArguments();
    BackFilterEvent backFilterEvent = (BackFilterEvent) bundle.getSerializable("listener");
    RandomRecyclerViewAdapter randomRecyclerViewAdapter  = new RandomRecyclerViewAdapter(getContext(), backFilterEvent);

In my adapter constructor, I set it to do the work once I call it from the activity class:

    this.backFilterEvent = backFilterEvent;
    backFilterEvent.setOnEventListener(new BackFilterEvent.OnEventListener() {
        @Override
        public ArrayList<FoodType> onEvent() {
            return foodTypes;
        }
    });

And in my back button in my activity class, I call the listener, which will trigger the work in the adapter class:

    back.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

                ArrayList<FoodType> foodTypes = backFilterEvent.doEvent(); }
Community
  • 1
  • 1
Simon
  • 19,658
  • 27
  • 149
  • 217