0

How YouTube handles the lifecycle of their tab's Fragments? When I tap on the tab it starts and continues loading the data even though I switched that tab. And when I reselect that tab again it does not reload it's view and data. I think that there are some boolean variables like didFeedLoad, which is then set true in onCreate? But in my opinion this is not elegant and good solution. What do ya think?

In my app instead of ViewPager and TabLayout I have BottomNavigationView, but I want to handle lifecycle like in YouTube Android App

Here is the code of navigation:

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, new OneFragment());
fragmentTransaction.commit();
BottomNavigationView bottomNavigationView =
            (BottomNavigationView) findViewById(R.id.bottom_navigation_view);

bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            Fragment fragment = null;
            switch (item.getItemId()) {
                case R.id.action_one:
                    fragment = new OneFragment();
                    break;
                case R.id.action_two:
                    fragment = new TwoFragment();
                    break;
                case R.id.action_three:
                    fragment = new ThreeFragment();
                    break;
                case R.id.action_four:
                    fragment = new FourFragment();
                    break;
                case R.id.action_five:
                    fragment = new FiveFragment();
                    break;
            }
            if (fragment != null) {
                FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                fragmentTransaction.replace(R.id.frame_layout, fragment);
                fragmentTransaction.commit();
            }
            return true;
        }
    });
madim
  • 774
  • 10
  • 22

3 Answers3

3

What you're looking for is the ViewPager .setOffscreenPageLimit(int limit)

From the Android Support Library (v4) Documentation:

Sets the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.

Default Value: 1

If you have 4 Tabs, and you want them all to remain idle and never be destroyed & recreated (like the YouTube app), you may want to set the limit to 3.

Taking YouTube app as a case-scenario (4 tabs), I believe that its ViewPager was defined more or less in this way:

ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(3);

Edit: Regarding BottomNavigationView - as long as you link it to a ViewPager, It doesn't matter whether you use this one or the TabLayout. But after a second reading I understand you're not using a ViewPager at all, so i'd like to know what you DO use so my assistance could be complete

(besides, why not using ViewPager? it looks like the perfect solution)

Community
  • 1
  • 1
Barak
  • 1,390
  • 15
  • 27
  • I do not want the swiping behaviour, and I also do not want to load data for other tabs. What I want is to make api request once when tab is selected and visible, and do not load other tab's data. If user selects other tab and the data is not loaded for the previous tab stop making request, and if user again reselects that tab the fragment has to know if the data is loaded for that tab or not. – madim Jan 27 '17 at 04:53
  • You can cancel the swiping behavior in ViewPager by creating one of your own (link below - great example). About the data load of other tabs - you can override the .setUserVisibleHint inside your fragment, which will occur when the fragment's visibility to the user is changed (link num 2 below). You may also use this for stopping previous tabs requests as well. http://stackoverflow.com/questions/9650265/how-do-disable-paging-by-swiping-with-finger-in-viewpager-but-still-be-able-to-s http://stackoverflow.com/questions/36353560/stop-android-tablayout-loading-next-page-automatically – Barak Jan 27 '17 at 12:27
0

I suspect that YouTube tab's fragments are normal fragments. When you switch tabs they can be (and probably are) killed. They just load data in the background (on main activity/different thread) and then cache/store that data locally, so when you switch again to same tab it is re-draw very quickly using stored/cached data.

0

You are loading a new instance of fragment every time you click on the bottom navigation view tab.

What you have to do is, once you create a single instance of the fragment,

then you have to just use hide and show methods of support fragment manager like this...

  { supportFragmentManager.beginTransaction().hide(currentFragment!!).show(prev_fragment).commit()
  }

Below I have written below the complete implementation.

 class MainActivity : AppCompatActivity() 

         {

      private lateinit var bottomNavigation:BottomNavigationView
 private var currentTag:String="null"
 private var currentFragment:Fragment?=null
  private lateinit var homeFragment:Fragment
 private lateinit var midFragment:Fragment
 private lateinit var profileFragment:Fragment
 override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

     init()
}

 private fun init() {
     homeFragment= HomeFragment()
     midFragment= MidFragment()
     profileFragment= ProfileFragment()

     bottomNavigation=findViewById(R.id.btm_nav)
     bottomNavigation.setOnNavigationItemSelectedListener(object :BottomNavigationView.OnNavigationItemSelectedListener{
         override fun onNavigationItemSelected(item: MenuItem): Boolean {
             when(item.itemId){
                 R.id.action_home->{


                     updateFragment(homeFragment,"home")
                 return true
                 }
                 R.id.action_mid->{

                     updateFragment(midFragment,"mid")
                 return true
                 }
                 R.id.action_profile->{
                     updateFragment(profileFragment,"profile")
        return true
                 }

             }
        return false

         }

     })
     updateFragment(homeFragment,"home")
 }

 fun updateFragment(fragment:Fragment, tag:String){

     if (currentTag.equals(tag)){
         return
     }
     var prev_fragment=supportFragmentManager.findFragmentByTag(tag)

     // if fragment is not present in stack
     if (prev_fragment==null){
         if (currentFragment==null){
             supportFragmentManager.beginTransaction().add(R.id.frag_container,fragment,tag).commit()
         }else{
             supportFragmentManager.beginTransaction().hide(currentFragment!!).add(R.id.frag_container,fragment,tag).commit()
         }

     }
   // if fragment is already added
     else{
         supportFragmentManager.beginTransaction().hide(currentFragment!!).show(prev_fragment).commit()
     }
     currentFragment=fragment
     currentTag=tag

 }

If you also want to maintain the back stack of the fragment , I have managed to do this with the help of stack. here is the GitHub link of the complete code. link

Aryan Dhankar
  • 179
  • 1
  • 10