0

I'm trying to pass a value from a fragment to an activity and I can't because I get an exception. On my fragment I have to choose one of the horoscopes which are presented in a FrameLayout. To do the communication between Activity and Fragment I'm using callback.

The exception is:

 java.lang.NullPointerException: Attempt to invoke interface method
 'void 
 com.converter.android.dailyhoroscope.HoroscopeChoice$OnInfoChangedListener.onInfoChanged(java.lang.String)'
 on a null object reference                                            
 at
 com.converter.android.dailyhoroscope.HoroscopeChoice$1.onClick(HoroscopeChoice.java:133)
 at android.view.View.performClick(View.java:5204)                     
 at android.view.View$PerformClick.run(View.java:21153)                
 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)

On the Fragment, I have the following code:

public class HoroscopeChoice extends DialogFragment {
public HoroscopeChoice() {
    }
    /******************************
     * Callback
     ********/
    public static void setOnInfoChangedListener(OnInfoChangedListener callback) {
        mCallback = callback;
    }

    public interface OnInfoChangedListener {
        public void onInfoChanged(String horosocopo);

    }
(...)
   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_horoscope_choice,
                container, false);

        Button aquarius;
        aquarius  = (Button) view.findViewById(R.id.aquarius1);

        final int id = view.getId();

        View.OnClickListener onClickListener = new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                String horoscopo = onClick2(v.getId());
                mCallback.onInfoChanged(horoscopo);
            }
        };

        aquarius.setOnClickListener(onClickListener);
        return view;
    }

    public String onClick2(int id)
    {
        String horoscopo="";

        if (id == R.id.aquarius1) {
            horoscopo = "Aquarius";
        }
      (...)
      return horoscope;
    }

On the activity, if I try to put setOnInfoChangedListener(this); trying to solve the exception I have, I get another error "Cannot resolve method setOnInfoChangedListener".

Activity:

public class SchedulerActivity extends Activity implements HoroscopeChoice.OnInfoChangedListener {

(...)
setOnInfoChangedListener(this);

    public void onInfoChanged(String horoscopo) {
        String sign="";
        mHoroscopeDisplay = (TextView) findViewById(R.id.dailyHoroscope4);
        mHoroscopeDisplay.setText(horoscopo);
        saveData(dHosocope, sign);
    }
}

Can you help me please?

porthfind
  • 1,581
  • 3
  • 17
  • 30
  • I have an answer here for you http://stackoverflow.com/questions/14247954/communicating-between-a-fragment-and-an-activity-best-practices/25392549#25392549 – Eenvincible Jun 18 '16 at 10:44

3 Answers3

0

The interface instance you get is null. If you want to call an interface method from Fragment,

  1. Create the interface and implement it in the Activity. (You've already done this)
  2. Create the interface instance in the fragment.

    public class MyFragment extends Fragment{
      private onInfoChangedListener listener;
    
      //you have to instantiate the listener variable in onAttach()
      @Override 
      public void onAttach(Context context){
          super.onAttach();
          try{
            listener=(SchedulerActivity)context;
          }catch(Throwable e){
            //interface might not be implemented
          }
      }
    
      //now you can use this in the onCreateView() method
      public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
           aquarius.setOnClickListener(new View.OnCLickListener{
                 @Override
                 public void onClick(View v){
                    try{
                       listener.onInfoChanged(horoscopo);
                    }catch(Throwable e){
                       //listener can be null
                    }
                 }
           });
    }
    
Malith Lakshan
  • 762
  • 6
  • 12
0

Hmmm, you might want a reminder of how interfaces work ;)

Fragment:

public class MyFragment extends Fragment {
    private OnInfoChangedListener listener;

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

    void aFunctionWhereSomethingHappen(){
        // fire event
        if(listener!=null)
            listener.onInfoChanged("text");
    }

    public interface OnInfoChangedListener {
        void onInfoChanged(String horosocopo);
    }

    public void setOnInfoChangedListener(OnInfoChangedListener listener) {
        this.listener = listener;
    }
}

In your Activity:

MyFragment fragment = new MyFragment();
fragment.setOnInfoChangedListener(new MyFragment.OnInfoChangedListener() {
    @Override
    public void onInfoChanged(String horosocopo) {
        // event
    }
});

I hope it's more clear !

EDIT:

You might also want to consider using libraries like EventBus or Otto, which were made exactly for this.

Omar Aflak
  • 2,918
  • 21
  • 39
0

Add the following code in your fragment.

@Override 
public void onAttach(Activity context){
   super.onAttach() 
   if(context instanceof OnInfoChangedListener)
        listener=(OnInfoChangedListener)context;
}
Arpit Ratan
  • 2,976
  • 1
  • 12
  • 20
  • I can't do this, I get @override in red "method does not override method from superclass" – porthfind Jun 18 '16 at 10:55
  • sorry, corrected my answer. It was activity not context. – Arpit Ratan Jun 18 '16 at 11:01
  • If I write Activity I get an exception every time I try to go to the fragment: FATAL EXCEPTION: main Process: com.converter.android.dailyhoroscope, PID: 30989 android.util.SuperNotCalledException: Fragment HoroscopeChoice{6b9709 #0 horoscope} did not call through to super.onAttach() – porthfind Jun 18 '16 at 11:30
  • modified. Please try again – Arpit Ratan Jun 18 '16 at 11:57
  • `onAttach(activity) is deprecated. Use `onAttach(Context)` instead. – Malith Lakshan Jun 18 '16 at 12:12
  • Just one more thing, now I don't have the exception but when I push the button (in the fragment) it should close the fragment and goes to the Activity...am I forgetting anything on my fragment code? – porthfind Jun 18 '16 at 13:33
  • i think you should try calling dismiss() after calling the callback method. – Arpit Ratan Jun 18 '16 at 13:42