1

I've 2 fragments in viewpager and I want to add callback methods using interface in both. I add the interface listener while initiating fragments in viewpager adapter but only the last fragment's is being called. That's why when I click on the MainActivity's menu option, only the Toast in MyFragB is being called even if MyFragA is showing.

Both Fragments... Only Activity calling MyFragB Toast is showing when wither fragment is opened

public class MyFragA extends Fragment implements FragmentCaller {

    private TextView myTxt;

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

    @Override
    public void CallFragment() {
        if(getActivity()!=null)
            Toast.makeText(getActivity(), "Activity calling MyFragA", Toast.LENGTH_SHORT).show();
    }
}

public class MyFragB extends Fragment implements FragmentCaller{

    private TextView myTxt;

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

    @Override
    public void CallFragment() {
        if(getActivity()!=null)
            Toast.makeText(getActivity(), "Activity calling MyFragB", Toast.LENGTH_SHORT).show();
    }
}

Main Activity

public class MainActivity extends AppCompatActivity {

    TabLayout tabs;
    ViewPager viewpager;

    FragmentCaller fragListerner = null;
    public interface FragmentCaller {
        void CallFragment();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tabs = (TabLayout)findViewById(R.id.tabs);
        viewpager = (ViewPager)findViewById(R.id.viewpager);
        SimpleFragmentPagerAdapter adapter = new SimpleFragmentPagerAdapter(this, getSupportFragmentManager());
        viewpager.setAdapter(adapter);
        tabs.setupWithViewPager(viewpager);

    } // onCreate ends



    public class SimpleFragmentPagerAdapter extends FragmentStatePagerAdapter {

        private Context mContext;

        public SimpleFragmentPagerAdapter(Context context, FragmentManager fm) {
            super(fm);
            mContext = context;
        }

        // This determines the fragment for each tab
        @Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
            if (position == 0) {
                fragment = new MyFragA();
                fragListerner = (FragmentCaller) fragment;
                return fragment;
            } else if (position == 1){
                fragment = new MyFragB();
                fragListerner = (FragmentCaller)fragment;
                return fragment;
            }
            return null;
        }

        // This determines the number of tabs
        @Override
        public int getCount() {
            return 2;
        }

        // This determines the title for each tab
        @Override
        public CharSequence getPageTitle(int position) {
            // Generate title based on item position
            switch (position) {
                case 0:
                    return mContext.getString(R.string.fraga);
                case 1:
                    return mContext.getString(R.string.fragb);
                default:
                    return null;
            }
        }

    }

    public boolean onCreateOptionsMenu(Menu menu) {

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.callback, menu);
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);
        switch (item.getItemId()){
            case R.id.call:
                if(fragListerner!=null){
                    if(fragListerner instanceof MyFragA){
                        fragListerner.CallFragment();
                    }else if(fragListerner instanceof MyFragB){
                        fragListerner.CallFragment();
                    }
                }
                break;
        }

        return true;
    }  


}
Vikash Chauhan
  • 746
  • 2
  • 9
  • 18
CodeAssasins
  • 227
  • 3
  • 15

2 Answers2

1

I used rick's answer from here.

public class MainActivity extends AppCompatActivity {

TabLayout tabs;
ViewPager viewpager;
public static int currentFrag=0;
SimpleFragmentPagerAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState)  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    tabs = (TabLayout)findViewById(R.id.tabs);
    viewpager = (ViewPager)findViewById(R.id.viewpager);
    adapter = new SimpleFragmentPagerAdapter(this, getSupportFragmentManager());
    viewpager.setAdapter(adapter);
    tabs.setupWithViewPager(viewpager);
    viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            System.out.println("sammy_current_position: "+position);
            currentFrag = position;
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

} // onCreate ends



public class SimpleFragmentPagerAdapter extends FragmentStatePagerAdapter {

    private Context mContext;

    public SimpleFragmentPagerAdapter(Context context, FragmentManager fm) {
        super(fm);
        mContext = context;
    }

    @Override
    public Fragment getItem(int position) {
        if (position == 0) {
            return new MyFragA();
        } else if (position == 1){
            return new MyFragB();
        }
        return null;
    }

    @Override
    public int getCount() {
        return 2;
    }

    // This determines the title for each tab
    @Override
    public CharSequence getPageTitle(int position) {
        // Generate title based on item position
        switch (position) {
            case 0:
                return mContext.getString(R.string.fraga);
            case 1:
                return mContext.getString(R.string.fragb);
            default:
                return null;
        }
    }

}

public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.callback, menu);
    return true;
}

public boolean onOptionsItemSelected(MenuItem item) {
    super.onOptionsItemSelected(item);
    switch (item.getItemId()){
        case R.id.call:
            if(currentFrag == 0) {
                MyFragA frag1 = (MyFragA)viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
                frag1.specialCase();
            }

            break;
    }

    return true;
}

}

CodeAssasins
  • 227
  • 3
  • 15
0

but only the last fragment's is being called

Of Course ! because at pos == 0 you are setting fragListerner = (FragmentCaller) fragment then at again in pos == 1 you re-set fragListerner = (FragmentCaller)fragment;. So this condition, fragListerner instanceof MyFragB will always be true!

        @Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
            if (position == 0) {
                fragment = new MyFragA();
                fragListerner = (FragmentCaller) fragment;
                return fragment;
            } else if (position == 1){
                fragment = new MyFragB();
                fragListerner = (FragmentCaller)fragment;
                return fragment;
            }
            return null;
        }

So, you are trying to communicate from activity to fragment

okay, if you still want to use interfaces, you can do it like that:

create an instance of your interface for each fragment! and in getItem assign them both,

@Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
            if (position == 0) {
                fragment = new MyFragA();
                fragAListerner = (FragmentCaller) fragment;
                return fragment;
            } else if (position == 1){
                fragment = new MyFragB();
                fragBListerner = (FragmentCaller)fragment;
                return fragment;
            }
            return null;
        }

But, there is an easier way to call fragment's methods from it's parent activity, which is like follows, for ex:

Fragment fragment = adapter.getItem(0); // MyFragA is at pos 0
fragment.<specific_function_name>(); 

Or, by using it's id!

MyFragA fragment = (MyFragA) getFragmentManager().findFragmentById(R.id.MyFragAId);
fragment.<specific_function_name>(); 

Or, by using it's tag!

MyFragA fragment = (MyFragA) getFragmentManager().findFragmentByTag("MyFragATag");
fragment.<specific_function_name>(); 
ATEF
  • 3,708
  • 3
  • 26
  • 50
  • I don't understand this. Why should I override interface method in activity? I want to do some action in fragment from activity. Like calling a method in fragment from activity. – CodeAssasins Sep 02 '17 at 10:00
  • Okay, I thought the converse!, I will update the answer! – ATEF Sep 02 '17 at 10:02
  • Hi. Checked and tried your answers. Here is the review: – CodeAssasins Sep 02 '17 at 10:43
  • Tried different instances of listener, didn't worked. 1. was unable to use adapter.getItem(0); as could not call a public method in first fragment. 2. can't use findFragmentById as not using framelayout 3. didn't used findFragmentByTag as it would require to set tag and in adapter this might have same result as interface – CodeAssasins Sep 02 '17 at 10:47
  • `different instances of listener, didn't worked` plz add more details! also by using `adapter.getItem(0)` you will need to cast returned value before calling the public method. – ATEF Sep 02 '17 at 11:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153519/discussion-between-atef-hares-and-codeassasins). – ATEF Sep 02 '17 at 11:14