Changing between Navigation Drawer fragments is slow

  • Replies:29
  • Forum posts: 27

Jun 1, 2016, 2:10:58 PM via Website

I have an app with a Navigation Drawer that uses fragments for each menu item.
Each time an item is clicked, I replace the current fragment.

The problem is that it takes a long time to show the new fragment after the user clicked.
The fragment that takes the longest to load is a fragment that has also tabs inside it with child fragments.
Is there any way I can speed up the loading of the fragments? (Perhaps initializing them beforehand, if this is possible?)

Here is my code:

protected override void OnCreate(Bundle bundle)
{
    drawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
    navigationView = FindViewById<NavigationView>(Resource.Id.nav_view);
    drawerLayout.DrawerClosed += DrawerLayout_DrawerClosed;
    var mainFab = FindViewById<FloatingActionButton>(Resource.Id.mainFab);
    mainFab.Click += MainFab_Click;

    var callFab = FindViewById<FloatingActionButton>(Resource.Id.callFab);
    callFab.Click += CallFab_Click;
    var messageFab = FindViewById<FloatingActionButton>(Resource.Id.messageFab);
    messageFab.Click += MessageFab_Click;
    // Initialize the ViewPager and set an adapter
    //var pager = FindViewById<ViewPager>(Resource.Id.pager);
    //pager.Adapter = new TabsFragmentPagerAdapter(SupportFragmentManager, fragments, titles);

    // Bind the tabs to the ViewPager
    //var tabs = FindViewById<PagerSlidingTabStrip>(Resource.Id.tabs);
    //tabs.SetViewPager(pager);

    navigationView.NavigationItemSelected += (sender, e) =>
    {
        e.MenuItem.SetChecked(true);
        //react to click here and swap fragments or navigate

        switch (e.MenuItem.ItemId)
        {
            case (Resource.Id.nav_home):
                ListItemClicked(0);
                break;

            case (Resource.Id.nav_halachot):
                ListItemClicked(1);
                break;

            case (Resource.Id.nav_times):
                ListItemClicked(2);
                break;

            case (Resource.Id.nav_siddur):
                ListItemClicked(3);
                break;
            case (Resource.Id.nav_compass):
                ListItemClicked(4);
                break;

            case (Resource.Id.nav_settings):
                ListItemClicked(5);
                break;
        }


        drawerLayout.CloseDrawers();                
    };

    if (bundle == null)
    {
        ListItemClicked(0);
        navigationView.Menu.GetItem(0).SetChecked(true);
        fragment = new HomeFragment();
        SupportFragmentManager.BeginTransaction()
        .Replace(Resource.Id.content_frame, fragment)
        .Commit();
    }
}

public override void OnBackPressed()
{

    if (drawerLayout.IsDrawerOpen((int)GravityFlags.Start))
    {
        drawerLayout.CloseDrawer((int)GravityFlags.Start);
    }
    else
    {
        base.OnBackPressed();
    }
}

private void ListItemClicked(int position)
{

    switch (position)
    {
        case 0:
            fragment = new HomeFragment();
            Title = "Home";
            SupportActionBar.Elevation = 8;
            break;
        case 1:
            fragment = new HalachaFragment();
            Title = "aaa";
            SupportActionBar.Elevation = 0;
            break;
        case 2:
            fragment = new TimesFragment();
            Title = "bbb";
            SupportActionBar.Elevation = 8;

            break;
        case 3:
            fragment = new SiddurFragment();
            Title = "ccc";
            SupportActionBar.Elevation = 8;
            break;
        case 4:
            fragment = new CompassFragment();
            Title = "ddd";
            SupportActionBar.Elevation = 8;
            break;
        case 5:
            fragment = new SettingsFragment();
            Title = "eee";
            break;
    }



}

private void DrawerLayout_DrawerClosed(object sender, DrawerLayout.DrawerClosedEventArgs e)
{
    SupportFragmentManager.BeginTransaction()
        .Replace(Resource.Id.content_frame, fragment).AddToBackStack("BACK")
        .Commit();

}

HalachaFragment.cs (The fragment that contains the tabs):

public class HalachaFragment : Fragment
{
    private ViewPager halachotPager;
    private PagerSlidingTabStrip tabs;

public HalachaFragment()
{
    this.RetainInstance = true;
}
public override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    // Create your fragment here
}

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    // Use this to return your custom view for this Fragment

    var view = inflater.Inflate(Resource.Layout.HalachaSection, container, false);

    var fragments = new Android.Support.V4.App.Fragment[]
   {
       new HalachotFragment(),
       new BooksFragment(),
   };

    var titles = CharSequence.ArrayFromStringArray(new[]
    {
            "הלכות",
            "ספרים",
    });

    halachotPager = view.FindViewById<ViewPager>(Resource.Id.halachotPager);

    halachotPager.Adapter = new TabsFragmentPagerAdapter(this.ChildFragmentManager, fragments, titles);
    halachotPager.OffscreenPageLimit = 2;
    halachotPager.SetCurrentItem(1, true);
    // Bind the tabs to the ViewPager
    tabs = view.FindViewById<PagerSlidingTabStrip>(Resource.Id.halachotTabs);

    tabs.SetViewPager(halachotPager);

    return view;

}

}

Hope someone can help me.

Thanks.

damponting44

Reply
  • Forum posts: 27

Jun 2, 2016, 8:05:32 PM via Website

Thanks, but I already did that, and replaced the fragments onDrawerClosed, but it still has a lag.

Reply
  • Forum posts: 266

Jun 2, 2016, 8:39:20 PM via Website

Do you use hardware acceleration? If not, add android:hardwareAccelerated="true" to the manifest.

— modified on Jun 2, 2016, 8:39:52 PM

damponting44

Reply
  • Forum posts: 266

Jun 2, 2016, 9:00:38 PM via Website

Sometimes a lot of data transfering between your test device and PC may slow it down. Did you try to disconnect usb cable after app installation?

damponting44

Reply
  • Forum posts: 27

Jun 2, 2016, 9:02:48 PM via Website

Yes, it happens even when the device isn't connected.

Reply
  • Forum posts: 8

Jun 2, 2016, 9:06:21 PM via Website

Well, good to read that here nice and good topic under discussion. I really like this.

Reply
  • Forum posts: 266

Jun 2, 2016, 9:37:19 PM via Website

@Amitai can you post some screenshots or video of your app?

Reply
  • Forum posts: 27

Jun 2, 2016, 10:43:47 PM via Website

Here's a link to a video of my app demonstrating this:

Notice that the second fragment takes the longest to load and that it shows the animation only on the second time I open it.

Thanks for your investigation and trying to help. I really appreciate it!

Vladimir S.

Reply
  • Forum posts: 266

Jun 2, 2016, 10:53:25 PM via Website

  1. Why do you use two TabsFragmentPagerAdapter. There are not tabs in top level of menu, try to use simple FragmentPagerAdapter, which can load all fragments in memory and theoretically would be better.
  2. Redusing images size to minimal suitable dimensions and using of the indexed colors can help

— modified on Jun 3, 2016, 7:32:17 AM

damponting44

Reply
  • Forum posts: 27

Jun 4, 2016, 8:29:12 PM via Website

Sorry, but I didn't quite understand you. Where am I using 'two' TabsFragmentPagerAdapter?

— modified on Jun 4, 2016, 8:43:40 PM

damponting44

Reply
  • Forum posts: 266

Jun 4, 2016, 8:39:20 PM via Website

Oh, i haven't noticed what there are comments...

Reply
  • Forum posts: 27

Jun 4, 2016, 9:15:50 PM via Website

Is there a way to initialize the fragment before opening it, so that once it is opened it will be loaded and won't lag?

Reply
  • Forum posts: 266

Jun 4, 2016, 9:22:24 PM via Website

Indexed color saves a lot of memory and storage space - your layout will be inflated more quickly. Most of grafics editor can convert pics to the indexed color format.

damponting44

Reply
  • Forum posts: 27

Jun 4, 2016, 9:43:08 PM via Website

Thanks. I managed to minimize the lag by hardware acceleration, removing animation and unnecessary code. Although even when I don't put any image in the second fragment (the one with the tabs), there is a small lag that doesn't happen when I click on the others or when I open the same fragment a second time.

Is there a way to initialize the fragment before opening it, so that once it is opened it will be loaded and won't lag?
Or any other suggestions?

Thanks!

— modified on Jun 4, 2016, 9:43:26 PM

damponting44

Reply
  • Forum posts: 266

Jun 4, 2016, 10:41:02 PM via Website

What if all fragments will be initialized in onCreate() ?

HomeFragment homeFragment;
HalachaFragment halachaFragment;
other fragments...........

Your Activity {

protected override void OnCreate(Bundle bundle)
{ 
other strings ..........
homeFragment = new HomeFragment();
halachaFragment = new HalachaFragment();
other fragments...........
}

private void ListItemClicked(int position)
{

    switch (position)
    {
        case 0:
            fragment = homeFragment;
            Title = "Home";
            SupportActionBar.Elevation = 8;
            break;
        case 1:
            fragment = halachaFragment;
            Title = "aaa";
            SupportActionBar.Elevation = 0;
            break;
other cases..........
}
}
.....................
}

— modified on Jun 4, 2016, 10:51:15 PM

Reply
  • Forum posts: 27

Jun 4, 2016, 10:56:51 PM via Website

Interesting idea, although sadly the lag is still there in the second fragment :(

Reply
  • Forum posts: 27

Jun 4, 2016, 10:58:16 PM via Website

Although it only happens on the first time it is clicked. Why is this?

Reply
  • Forum posts: 266

Jun 4, 2016, 11:05:03 PM via Website

When you select other fragment, previous one is not destroyed, but only detached and when it is recalled the FragmentManager extracts it from the backstack.

public override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    // Create your fragment here
}

Maybe comment is right? :)

— modified on Jun 4, 2016, 11:08:02 PM

Reply
  • Forum posts: 27

Jun 4, 2016, 11:07:47 PM via Website

Oh, I see. If any other idea comes up, I'll be glad. If you want to see some of my other code, I can post it.

Thanks!

Reply
  • Forum posts: 266

Jun 4, 2016, 11:14:41 PM via Website

I have edited my post and are not sure you read it after...

Maybe you need to init tab fragments in onCreate of HalachFragment? There is comment "Create your fragment here".

Reply
  • Forum posts: 27

Jun 4, 2016, 11:25:03 PM via Website

Tried changing it to this:

public class HalachaFragment : Fragment
{
    private ViewPager halachotPager;
    private PagerSlidingTabStrip tabs;
    private Fragment[] fragments;
    TabsFragmentPagerAdapter tabsAdapter;

    public HalachaFragment()
    {
        this.RetainInstance = true;
    }
    public override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        fragments = new Fragment[]
       {
           new HalachotFragment(),
           new BooksFragment(),
       };

        var titles = CharSequence.ArrayFromStringArray(new[]
       {
                "הלכות",
                "ספרים",
        });

        tabsAdapter = new TabsFragmentPagerAdapter(ChildFragmentManager, fragments, titles);
        // Create your fragment here
    }

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        // Use this to return your custom view for this Fragment

        var view = inflater.Inflate(Resource.Layout.HalachaSection, container, false);


        halachotPager = view.FindViewById<ViewPager>(Resource.Id.halachotPager);

        halachotPager.Adapter = tabsAdapter;
        halachotPager.OffscreenPageLimit = 2;
        halachotPager.SetCurrentItem(1, true);
        // Bind the tabs to the ViewPager
        tabs = view.FindViewById<PagerSlidingTabStrip>(Resource.Id.halachotTabs);

        tabs.SetViewPager(halachotPager);

        return view;

    }

Is this what you meant? If so, it doesn't help. :(

Reply
  • Forum posts: 27

Jun 5, 2016, 7:44:49 PM via Website

I thought maybe it's a problem with my layout, so I'm posting my xml code:

Main:
image

HalachaSection (for HalachaFragment):
image

I know my layout is a bit messed up. If you could help me clean it a bit and maybe rearrange it, maybe that will help with the performance (also to solve the weird issue I have with the shadows which is why I need to change the Support Action Bar Elevation each time).

Thanks!

Reply
  • Forum posts: 70

Oct 6, 2016, 2:28:12 PM via Website

Much appreciated. I figured out how to minimize the slack by equipment speeding up, evacuating movement and pointless code. Albeit notwithstanding when I don't put any picture in the second part (the one with the tabs), there is a little slack that doesn't happen when I tap on the others or when I open the same piece a second time.

Is there an approach to introduce the piece before opening it, so that once it is opened it will be stacked and won't slack?

Then again whatever other recommendations?

Much appreciated!

Reply
  • Forum posts: 1

Nov 14, 2019, 6:19:26 PM via Website

Hi everyone,

I have read all the comments in this forum because I had the same trouble than Amitai Rosenberg, and I know this thread is already old.

I have follow all the steps descripted here but its not resolved until I had take off all the images that had much KB and MB from folder "drawable" and only it stay that I used and Yeah!! Its works, the app work fluid.
Well that is my experience.
Greetings

— modified on Nov 14, 2019, 6:21:16 PM

Reply