9

Hi I'm making an app with A fragment and few child fragment inside it using tablayout and viewpager. The problem is all my child fragment (from Tablayout) always execute (load all the code inside whenever user click the parent fragment. How to get the child fragment only load whenever the the user slide to it (for example I have 2 tab, content in tab 2 only load when user slide to tab 2)

Here is my parent fragment code

public class ManageEventFragment extends Fragment {


    public ManageEventFragment() {
        // Required empty public constructor
    }


    TabLayout tabLayout;
    ViewPager viewPager;

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

        viewPager = (ViewPager) viewFragment.findViewById(R.id.viewPager);

        tabLayout = (TabLayout) viewFragment.findViewById(R.id.tabLayout);

        viewPager.setAdapter(new CustomAdapter(getChildFragmentManager(), getContext()));
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

        return viewFragment;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {

        //        tabLayout.setupWithViewPager(viewPager);
        tabLayout.post(new Runnable() {
            @Override
            public void run() {
                tabLayout.setupWithViewPager(viewPager);
            }
        });

        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
            }
        });

        if (ViewCompat.isLaidOut(tabLayout)) {
            tabLayout.setupWithViewPager(viewPager);
        } else {
            tabLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    tabLayout.setupWithViewPager(viewPager);
                    tabLayout.removeOnLayoutChangeListener(this);
                }
            });
        }

        super.onActivityCreated(savedInstanceState);

    }


    //TabLayout and ViewPager class
    private class CustomAdapter extends FragmentPagerAdapter {

        private String fragments[] = {"Edit Event", "Create Event"};

        public CustomAdapter(FragmentManager fragmentManager, Context context) {
            super(fragmentManager);
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return new EditEventFragment();
                case 1:
                    return new CreateEventFragment();
                default:
                    return null;
            }
        }

        @Override
        public int getCount() {
            return fragments.length;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return fragments[position];
        }

    }

}

And my child fragment code. I want these code only execute whenever the user slide to the child tab. Any help is much appreciate, Thanks

@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        //Initializing our listEvents list
        listEvents = new ArrayList();

        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(getContext());
        recyclerView.setLayoutManager(layoutManager);

        adapter = new EventAdapterEdit(getContext(),listEvents);
        recyclerView.setAdapter(adapter);


        requestQueue = Volley.newRequestQueue(getContext());

        adapter = new EventAdapterEdit(getContext(),listEvents);
        recyclerView.setAdapter(adapter);

        getEventDetailRespond(requestQueue);
Lê Khánh Vinh
  • 2,591
  • 5
  • 31
  • 77
  • `@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); }` – Kosh Dec 28 '15 at 02:08
  • thanks for yrs rep. Can u describe a bit more detail. I need to put the above child fragment code on @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); }? – Lê Khánh Vinh Dec 28 '15 at 02:10
  • When will android just add a callback to the tabView? – Zapnologica Jan 04 '17 at 19:32

2 Answers2

5
@Override public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
}

you could use above method within your fragment that is within your ViewPager Adapter

if(isVisibleToUser){//dosomething when the fragment is visible}
else{//dosomething else.}

be aware to do not initialize views there or anything rather, init your views within onViewCreated and call the method that you wanna execute on setUserVisibleHint. another ugly way is to add a scroll listener to your ViewPager and get the current item position and trigger an action that is within the fragment. to get the fragment from the ViewPager Adapter you can do such :

 MyFragment frag = (MyFragment) pager.getAdapter().instantiateItem(pager, position);

then you could call a method that is within MyFragment

Kosh
  • 6,140
  • 3
  • 36
  • 67
  • I tried yrs 1st method but does not seem to work. I move all the view code to OnCreateView and left only the method to fetch data getEventDetailRespond(requestQueue); inside @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); } but got null pointer error (I have progressbar.setvisibillity inside the getEventDetailRespond – Lê Khánh Vinh Dec 28 '15 at 02:40
  • instead of using getChildFragmentManager() could u call getActivity().getSupportFragmentManager() and see if that solve it? however i still encourage you to do some debugging on the answer i did provide. – Kosh Dec 28 '15 at 02:42
  • seem to work with simple test Toast message but when I put my fetch data method. return null pointer. here is my method code and the error shown https://docs.google.com/document/d/16APWQippnSNr0_BWqDQd36kzRA6IpbsLSHKIt0xgEFY/edit – Lê Khánh Vinh Dec 28 '15 at 02:57
  • your issue is within this line `ProgressBar.setVisibility(int)` as i mentioned do initialize your views onViewCreated and `setUserVisibleHint ` its called before `onViewCreated` so check against null stuff. – Kosh Dec 28 '15 at 02:59
  • But the problem is that I need the progressBar to be visible whenever the method is fetching data from server. when receive the respond from server, the progress bar will be disappear. – Lê Khánh Vinh Dec 28 '15 at 03:02
4

The Viewpager by default loads the adjacent fragment to ensure make the app smooth, so that when the user swipe to the fragments (already loaded) it is there. To change is default behavior, use viewpager.setOffscreenPageLimit(int limit) where limit is how many fragment next to the one you are on will be preloaded. Hope this helps

Tin Tran
  • 2,265
  • 1
  • 14
  • 17
  • thanks a lot. So by default if I have 3 fragment, only first 2 fragment will be loaded when user click parent fragment? where to put the viewsetOffscreenPageLimit(int limit) (on parent or child)? can give a bit detail how to implement this? – Lê Khánh Vinh Dec 28 '15 at 03:26
  • I made a typo on my answer. already edited. You can call that method on the ViewPager. – Tin Tran Dec 28 '15 at 03:29
  • I seem not to work. I have 2 child fragment. When I put viewpager.setOffscreenPageLimit(0) in my parent OnCreateView. all the code from child fragment 2nd tab is still loaded whenever user click parent fragment – Lê Khánh Vinh Dec 28 '15 at 03:37
  • 1
    @LêKhánhVinh The minimum off screen page limit is 1. `ViewPager` is going to load stuff off screen so that it's ready when the user starts to scroll. You cannot avoid this. – Karakuri Dec 28 '15 at 04:08
  • thanks a lot. so If I have like 3 tab then the 3rd will not be automatic load when set is default 1? – Lê Khánh Vinh Dec 28 '15 at 04:57
  • @LêKhánhVinh Yes Thats is true. Can I know why you want the system to not preload your fragment ? – Tin Tran Dec 28 '15 at 05:00
  • that because I want to pass the data get from the first child pass to the 2nd or 3rd child (like update data view based on user change) – Lê Khánh Vinh Dec 28 '15 at 05:03
  • @LêKhánhVinh: I have a cameraview which gets activated even when am in another tab. – Harish Vishwakarma Apr 21 '17 at 02:45
  • i was searching so many sites, books to find out why the adjucent fragements are called but i did't found any answer. but now thanks to " TIn Tan " i understood it. – gsharew Aug 03 '22 at 12:10