ViewPager, DestroyItem, and NullPointerException

Nathan Sokalski 4,126 Reputation points
2022-03-31T00:11:56.107+00:00

I am relatively new to using ViewPager, so I may be missing something else, but here is the best description I can come up with. My PagerAdapter is not expected to have very many items (during my tests, it only has 4), and prior to assigning the adapter to the ViewPager I set OffscreenPageLimit to the number of items that will be in the adapter. When I need to update the ViewPager, I assign a new instance of the PagerAdapter to the ViewPager's Adapter. However, this is causing a Java.Lang.NullPointerException in the DestroyItem method of my PagerAdapter. Here is my DestroyItem:

public override void DestroyItem(ViewGroup container, int position, Object @object) { container.RemoveViewAt(position); }

I am not sure what I should be putting in DestroyItem, especially since I am creating a new instance of the PagerAdapter anyway. What is the problem? Should I be doing something different in DestroyItem?

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,326 questions
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 72,251 Reputation points Microsoft Vendor
    2022-03-31T07:04:31.093+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    If you create custom FragmentPagerAdapter, you do not need to override the DestroyItem to recycle fragments manually.

    The default for the setOffScreenPageLimit should already be one. This means that Android will destroy old fragments when memory runs low. As long as you do not have a memory issue, just leave it be.

    If you want to recycle other disappeared Fragments automatically, you can extend FragmentStatePagerAdapter, Entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.

    Here is a document about achieving a custom FragmentPagerAdapter in Xamarin. You can refer to it.

    https://learn.microsoft.com/en-us/xamarin/android/user-interface/controls/view-pager/viewpager-and-fragments#create-the-adapter

    If FragmentStateAdapter is deprecated,
    Switch to androidx.viewpager2.widget.ViewPager2 and use androidx.viewpager2.adapter.FragmentStateAdapter instead.

    If you want to use ViewPager2, you need to install Xamarin.AndroidX.ViewPager2nuget package:

    Best Regards,
    Leon Lu


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Graham McKechnie 321 Reputation points
    2022-04-03T22:23:28.43+00:00

    Typical of support here, too many recommendations of using outdated techniques. You shouldn't really waste your time with ViewPager, you should be using ViewPager2. See AndroidX.ViewPager2.Widget which uses FragmentStateAdapter. There are plenty of Android ViewPager2 and FragmentStateAdapter tutorials around.


  3. Graham McKechnie 321 Reputation points
    2022-04-04T00:47:00.18+00:00

    ViewPager2 will certainly work with Activities, however, I wouldn't waste time with multi-activity development because modern android development is Single Activity/multiple fragments using the Navigation component.

    So even though there are 3 constructors for FragmentStateAdapter including one that takes a FragmentActivity, the constructor of your FragmentStateAdpter should inherit from is FragmentStateAdapter(FragmentManager fragmentManager, AndroidX.Lifecycle.Lifecycle lifecycle)

    Because FragmentStateAdapter is an abstract class you then just need to override both ItemCount and CreateFragment.

    The code snippet below is an example of how you implement them.

    public class MonitorsViewPagerFragmentAdapter : FragmentStateAdapter
        {
    
            private readonly int itemCount;
    
            public MonitorsViewPagerFragmentAdapter(FragmentManager fragmentManager, Lifecycle lifecylce, int itemCount) : base(fragmentManager, lifecylce)
            {
                this.itemCount = itemCount;
            }
    
            // implement inherited abstract member ItemCount
            public override int ItemCount => itemCount;
    
            // implement inherited abstract member - CreateFragment of Viewpager2 replaces GetItem of ViewPager. Creating a new instance each time instead of reusing instances as was done in ViewPager
            public override Fragment CreateFragment(int position)
            {
                return position switch
                {
                    0 => MonitorFragment.NewInstance(),
                    1 => ContinuousMonitoringFragment.NewInstance(),
                    2 => NonContinuousMonitoringFragment.NewInstance(),
                    _ => null,
                };
            }
        } 
    

    And an example of calling it from the fragment that is using the FragmentStateAdapter

    monitorsViewPagerFragmentAdapter = new MonitorsViewPagerFragmentAdapter(ChildFragmentManager, ViewLifecycleOwner.Lifecycle, 3);
    
    0 comments No comments