How can make my ViewPager load only one page at a time ie setOffscreenPageLimit(0);
Asked Answered
M

9

44

I understand the lowest number I can give setOffscreenPageLimit(int) is 1. but I need to load one page at a time because memory problems.

Am i going to have to use the old style tabhost etc? or is there a way/hack I can make my viewPager load one page at a time?

My Adapter extends BaseAdapter with the ViewHolder patern.

Matterhorn answered 30/9, 2013 at 14:31 Comment(2)
see the link [#17949181 [1]: #17949181Pippo
Check this answer . It solves the problem of me.Carnes
F
42

I was having the same problem and I found the solution for it:

Steps:

1) First Download the CustomViewPager Class from this link.

2) Use that class as mentioned below:

In Java:

CustomViewPager mViewPager;
mViewPager = (CustomViewPager) findViewById(R.id.swipePager);
mViewPager.setOffscreenPageLimit(0);

In XML:

<com.yourpackagename.CustomViewPager 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipePager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Now only one page will be loaded at once.

P.S: As per the question's requirement, I have posted the solution for Viewpager. I haven't tried the same with TabLayout yet. If I will find any solution for that I will update the answer.

In this file, KeyEventCompat is used it may not be found by the Android studio because KeyEnentCompat class was deprecated in API level 26.0.0 so you need to replace KeyEventCompat with event for more details you can view https://developer.android.com/sdk/support_api_diff/26.0.0-alpha1/changes/android.support.v4.view.KeyEventCompat

Frenzy answered 7/6, 2017 at 6:24 Comment(26)
Not able to setup with TabLayout, Please adviseAfroasian
@RRR_1173, Use any general example for viewpager and just replace your Viewpager to CustomViewPager. you can find the general example here: androidhive.info/2013/10/… You just need to give the CustomClass.Frenzy
tabLayout.setupWithViewPager(customeViewPager); here Tablayout not accepting the Custom class.Afroasian
Not able to setup with TabLayout, Please adviseApocalypse
Working fine. Thank you very much. But If use pager indicator, that position not changing.Mcbride
Works fine. Thank You very much. @Mcbride for changing the position u need to change the OnPageChangeListener to TabLayout.TabLayoutOnPageChangeListener and also add viewPager.setOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout){}); to the viewpagerOverreact
Thanks man. You saved my life!!! You deserve an Oscar!! I have been struggling to make it work for 5 days!!!Tour
How to do vertical scroll instead Horizontal using this class ?Felony
@MaheshCheliya : Have a look at this answer. Maybe it is useful to you. https://mcmap.net/q/56833/-android-vertical-viewpager Note: All you need to change is, in that answer, they extend ViewPager. Instead of that, you need to extend CustomViewPager.Frenzy
@RonakThakkar I need "one page will be loaded at once" thats why i am using this class, if i extend View Pager, it is always load minimum 2 pageFelony
thats why i have written note in previous comment: Note: All you need to change is, in that answer, they extend ViewPager. Instead of that, you need to extend CustomViewPager. lets try once.Frenzy
i tried to extends customeviewpager Instead ViewPager, but setPageTransformer method is not resolve in Customviewpager, so how to achieve vertical swipe with customeviewpager ?Felony
@MaheshCheliya : lets join this room : chat.stackoverflow.com/rooms/173214/…Frenzy
@RonakThakkar how to add this with TabLayout. Thanks for help in advance.Butlery
@RonakThakkar I am using nested fragment.Butlery
@Afroasian how did you solve that problem? Can you please help me out with this?Butlery
Actually, I haven't tried this with TabLayout yet. Once I do it for Tab I will edit the answer.Frenzy
@Butlery check my answer, no need to add custom code, you can work with your existing code.Afroasian
Great solution, you save my dayHousum
@Afroasian t have you got any solution for this onetabLayout.setupWithViewPager(customeViewPager); here Tablayout not accepting the Custom class. –Zellazelle
Hi @Overreact any solution for this one onetabLayout.setupWithViewPager(customeViewPager); here Tablayout not accepting the Custom classZellazelle
@RonakThakkar . Thanks a lot .It just saves my day.I was looking for making fragment dynamic for viewPager. But later i found that viewPager creates two instances or initiates two view at the starting time but i was bound to create just one.Your CustomViewPager class just did this amazingly. Now i can use a single fragment with different content in different page of viewPager.Cecelia
I got crash all the time E/Parcel: Class not found when unmarshalling: android.support.v4.view.ViewPager$SavedState does any one can help?Pelagias
Does anyone know how to achieve the implementation of PageTransformer in this one?Diplodocus
Great solution buddy, Worked for me.Ceilidh
Great solution for ViewPager with FragmentStatePagerAdapterClements
D
19

As far as I know, that is not possible when using the ViewPager. At least not, when you want your pages to be swipe-able.

The explaination therefore is very simple:

When you swipe between two pages, there is a Point when both pages need to be visible, since you cannot swipe between two things when one of those does not even exist at that point.

See this question for more: ViewPager.setOffscreenPageLimit(0) doesn't work as expected

CommonsWare provided a good explaination in the comments of his answer.

Dialectology answered 30/9, 2013 at 14:40 Comment(2)
What If I dont want the swipe feature of view pager ? . I am using NonSwipeableViewPager like this github.com/nuuneoi/TheCheeseLibrary/blob/master/src/main/java/…Kutzenco
Then don't use a viewpager ... Just use a fragment pager or a fragment state pager adapter with a tablayoutJenifer
K
13

but I need to load one page at a time because memory problems.

That presumes that you are getting OutOfMemoryErrors.

Am i going to have to use the old style tabhost etc?

Yes, or FragmentTabHost, or action bar tabs.

or is there a way/hack I can make my viewPager load one page at a time?

No, for the simple reason that ViewPager needs more than one page at a time for the sliding animation. You can see this by using a ViewPager and swiping.

Or, you can work on fixing your perceived memory problems. Assuming this app is the same one that you reported on earlier today, you are only using 7MB of heap space. That will only result in OutOfMemoryErrors if your remaining heap is highly fragmented. There are strategies for memory management (e.g., inBitmap on BitmapOptions for creating bitmaps from external sources) that help address such fragmentation concerns.

My Adapter extends BaseAdapter with the ViewHolder patern.

BaseAdapter is for use with AdapterView, not ViewPager.

Kp answered 30/9, 2013 at 14:39 Comment(0)
D
6

I have an Answer for this. The above said method setUserVisibleHint() is deprecated and you can use setMaxLifecycle() method. For loading only the visible fragment you have to set the behaviour to BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT in the viewpager adapter. ie; in the Constructor. And for handling the fragment use onResume() method in the fragment.

In this way you can load only one fragment at a time in the viewpager.

public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
    super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}

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

@Override
public Fragment getItem(int position) {
    return ArrayListFragment.newInstance(position);
}

}

In Kotlin:

class MyAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT )

Also use with FragmentPagerAdapter (now deprecated) in same way

Delacroix answered 24/3, 2020 at 13:51 Comment(3)
Can you explain in detail?Oversubtle
your answer is somewhere helpful for me please give more explainationMassasauga
This answer was the only helpful answer wherein we did not have to override any deprecated methods or create a custom view.Hercegovina
P
3

By using this method you can load one page at time in tab layout with view pager`

  @Override
    public void onResume() {
        super.onResume();
        if (getUserVisibleHint() && !isVisible) {
            Log.e("~~onResume: ", "::onLatestResume");
           //your code
        }
        isVisible = true;
    }

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

        if (isVisibleToUser && isVisible) {
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                   //your code
                }
            }, 500);

        }
    }

`

Procurator answered 31/10, 2018 at 6:36 Comment(0)
A
2

Override the setUserVisibleHint and add postDelayed like below in your every fragments.

override fun setUserVisibleHint(isVisibleToUser: Boolean) {
    if (isVisibleToUser)
        Handler().postDelayed({
            if (activity != null) {
                // Do you stuff here 
            }
        }, 200)
    super.setUserVisibleHint(isVisibleToUser)
}

I can manage by this way and its working fine now for me.

Afroasian answered 20/10, 2018 at 7:47 Comment(1)
Any example plz?Explain
H
1

First, copy in the SmartFragmentStatePagerAdapter.java which provides the intelligent caching of registered fragments within our ViewPager. It does so by overriding the instantiateItem() method and caching any created fragments internally. This solves the common problem of needing to access the current item within the ViewPager.

Now, we want to extend from SmartFragmentStatePagerAdapter copied above when declaring our adapter so we can take advantage of the better memory management of the state pager:

public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
    // Sparse array to keep track of registered fragments in memory
    private SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

    public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    // Register the fragment when the item is instantiated
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

    // Unregister when the item is inactive
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    // Returns the fragment for the position (if instantiated)
    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}


// Extend from SmartFragmentStatePagerAdapter now instead for more dynamic ViewPager items
    public static class MyPagerAdapter extends SmartFragmentStatePagerAdapter {
    private static int NUM_ITEMS = 3;

        public MyPagerAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }

        // Returns total number of pages
        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        // Returns the fragment to display for that page
        @Override
        public Fragment getItem(int position) {
            switch (position) {
            case 0: // Fragment # 0 - This will show FirstFragment
                return FirstFragment.newInstance(0, "Page # 1");
            case 1: // Fragment # 0 - This will show FirstFragment different title
                return FirstFragment.newInstance(1, "Page # 2");
            case 2: // Fragment # 1 - This will show SecondFragment
                return SecondFragment.newInstance(2, "Page # 3");
            default:
                return null;
            }
        }

        // Returns the page title for the top indicator
        @Override
        public CharSequence getPageTitle(int position) {
            return "Page " + position;
        }

    }
Homebody answered 3/9, 2019 at 6:55 Comment(0)
S
0

You actually don't need a custom ViewPager.

I had the same issue and I did like this.

  • Keep the setOffscreenPageLimit() as 1.
  • Use fragment's onResume and onPause lifecycle methods.

Initialize and free-up memories on these lifecycle methods.

Soissons answered 23/9, 2020 at 10:26 Comment(0)
C
-2

I know this is an old post, but I stumbled upon this issue and found a good fix if your loading fragments. Simply, check if the user is seeing the fragment or not by overriding the setUserVisibleHint(). After that load the data.

    @Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        getData(1, getBaseUrl(), getLink());
    }
}
Call answered 3/11, 2016 at 19:24 Comment(2)
A fragment can be visible but not initialized yet, this solution will cause issues.Riess
You can always add a boolean check and re-call it from the oncreate method. I've been using this solution for more than a month now, the app runs great.Call

© 2022 - 2024 — McMap. All rights reserved.