kobbycoder
kobbycoder

Reputation: 682

Interface java/Android not working from child to parent fragment

I am trying to communicate within two fragments, the main and the child. however when i declare the interface in the child to pass values to the main fragment it works fine but when i want to pass from the main to the childfragment it doesn't work. by the way the fragment is in my MainActivity. Thanks for your help.

The error message is:

Caused by: java.lang.IllegalArgumentException: com.example.example.example.MainActivity must implement interface NotifyOnTutorialPageSelected

so is there a way to pass value without using static function directly? because what i have noticed that only the parent can implement the interface so what can i do it if i want to make it with interface? by the way it is for learning purposes.

CODE:

//MAin activity is something that calls only the mainfragment
public class MainActivity extends ActionBarActivity {

    FragmentManager fragmentManager;
    TutorialFragment tutorialFragment;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActionBar actionBar = getSupportActionBar();
        actionBar.hide();


        fragmentManager = getSupportFragmentManager();    
        fragmentManager.findFragmentById(R.id.card_message_frag);
        tutorialFragment = (TutorialFragment) fragmentManager.findFragmentById(R.id.tutorial_frag);

    }
}

FIRST CLASS (called by MainActivity)

public class TutorialFragment extends Fragment implements ViewPager.OnPageChangeListener, OnTabSelected {

    FragmentManager fragmentManager;
    MultiTabFragment multiTabFragment;
    NotifyOnTutorialPageSelected notifyOnTutorialPageSelected;
    View tab ;
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_tutorial, container, false);
        fragmentManager = getChildFragmentManager();
        multiTabFragment = (MultiTabFragment) fragmentManager.findFragmentById(R.id.multi_tabs_frag);
        tab.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //Log.e("clicked tab# ", "" + tabIndex);
                        onTabSelected.onTabSelected(tabIndex);
                    }
                });
        return view;
    }

    @Override
    public void onPageSelected(int position) {  
        notifyOnTutorialPageSelected.notifyOnTutorialPageSelected(position); // do something so can communicate with the child fragment
    }


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

        if (getActivity() instanceof NotifyOnTutorialPageSelected) {
            notifyOnTutorialPageSelected = (NotifyOnTutorialPageSelected) getActivity();
        } else if (getParentFragment() instanceof OnTabSelected) {
            notifyOnTutorialPageSelected = (NotifyOnTutorialPageSelected) getParentFragment();
        } else {
            throw new IllegalArgumentException(activity + " must implement interface " + NotifyOnTutorialPageSelected.class.getSimpleName());
        }

    }

    @Override
    public void onDetach() {
        notifyOnTutorialPageSelected = null;
        super.onDetach();
    }

    @Override
    public void onTabSelected(int index) {
        Log.e("INDEX_PASSED", "" + index);
        pager.setCurrentItem(index);
    }
}

SECOND CLASS (called by TutorialFragment)

public class MultiTabFragment extends Fragment implements NotifyOnTutorialPageSelected{
    private OnTabSelected onTabSelected;

    final int totalTabs = 4;

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


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

        if (getActivity() instanceof OnTabSelected) {
            onTabSelected = (OnTabSelected) getActivity();
        } else if (getParentFragment() instanceof OnTabSelected) {
            onTabSelected = (OnTabSelected) getParentFragment();
        } else {
            throw new IllegalArgumentException(activity + " must implement interface " + OnTabSelected.class.getSimpleName());
        }
    }

    @Override
    public void onDetach() {
        onTabSelected = null;
        super.onDetach();
    }

    @Override
    public void notifyOnTutorialPageSelected(int index) {
        deselectPreviousTab(index);
    }

SOLUTION:

Since nobody answered the question I will leave the answer right here if someone has similar difficulty. I solved this problem by implementing the interface to the MainActivity so the main activity would call the childclass and call the method:

//MAin activity is something that calls only the mainfragment
public class MainActivity extends ActionBarActivity implements NotifyOnTutorialPageSelected{

    FragmentManager fragmentManager;
    TutorialFragment tutorialFragment;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActionBar actionBar = getSupportActionBar();
        actionBar.hide();


        fragmentManager = getSupportFragmentManager();    
        fragmentManager.findFragmentById(R.id.card_message_frag);
        tutorialFragment = (TutorialFragment) fragmentManager.findFragmentById(R.id.tutorial_frag);

    }

@Override
    public void notifyOnTutorialPageSelected(int index) {
        FragmentManager fragmentChildManager = tutorialFragment.getChildFragmentManager();
        MultiTabFragment multiTabFragment = (MultiTabFragment) fragmentChildManager.findFragmentById(R.id.multi_tabs_frag);
        multiTabFragment.deselectPreviousTab(index);
    }
}

it worked for me or at least for what i wanted, if someone has a different solution please tell me, Thanks.

Upvotes: 1

Views: 1891

Answers (1)

George Mulligan
George Mulligan

Reputation: 11923

You are throwing the exception yourself because your activity does not implement the NotifyOnTutorialPageSelected interface and your parent fragment must not implement the OnTabSelected interface.

The following code needs to be fixed to where one of the first two conditions is true. You have a potential mistake in your else if statement by the way since you are only checking if it is an instanceOf OnTabSelected but then cast the parent fragment as a NotifyOnTutorialPageSelected:

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

        if (getActivity() instanceof NotifyOnTutorialPageSelected) {
            notifyOnTutorialPageSelected = (NotifyOnTutorialPageSelected) getActivity();
        } else if (getParentFragment() instanceof OnTabSelected) {
            notifyOnTutorialPageSelected = (NotifyOnTutorialPageSelected) getParentFragment();
        } else {
            throw new IllegalArgumentException(activity + " must implement interface " + NotifyOnTutorialPageSelected.class.getSimpleName());
        }

    }

Looking at your code I do not see how you have a child fragment since your tutorial fragment is not creating one.

Are you trying to have a single activity that displays two fragments that communicate?

If so take a look at the Android Documentation on how to do that using an interface.

EDIT:

You are likely going to find through this learning experience that there is a lot more wrong with your code. But to get you moving forward and away from your current error remove the onAttach method in your TutorialFragment fragment since it is wrong anyway. If you are going to have your Activity class implement the callback interfaces that is where it would go. Since you aren't doing it that way then there is no point in checking if your activity implements that particular interface.

Your MultiTabFragment.onAttach method only needs the following unless you are going to put the fragment directly into an activity sometimes:

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

    if (getParentFragment() instanceof OnTabSelected) {
        onTabSelected = (OnTabSelected) getParentFragment();
    } else {
        throw new IllegalArgumentException("Parent Fragment must implement interface " + OnTabSelected.class.getSimpleName());
    }
}

Finally since you are already keeping a reference to your MultiTabFragment in your TutorialFragment remove the NotifyOnTutorialPageSelected notifyOnTutorialPageSelected; and call to the fragment directly.

@Override
public void onPageSelected(int position) {  
    multiTabFragment.notifyOnTutorialPageSelected(position); // do something so can communicate with the child fragment
}

Upvotes: 1

Related Questions