Java 如何仅在 ViewPager 被选中时加载片段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19485848/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 17:39:28  来源:igfitidea点击:

how load fragment in ViewPager only when its selected

javaandroidandroid-fragmentsandroid-viewpager

提问by Javier

I'm using 3 Fragmentsinside a Viewpager, the problem is that I am loading big data in an Asynctaskand loaders. On devices like HTC one, it works fine, however, on low-end devices, it takes a lot of time. This is mainly because when I implement the pagerAdapter, I put the Fragments inside an ArrayList, this force the fragments instantiate when the main activity is loaded. What I need is that it just "load" the first fragment (main) and when the user Swype, load the other fragment. its any way to achieve this? this is my pageAdapater

Fragments在 a 中使用 3 Viewpager,问题是我在 aAsynctask和加载器中加载大数据。在像 的设备上HTC one,它工作正常,但是,在低端设备上,它需要很多时间。这主要是因为当我实现 时pagerAdapter,我将 Fragments 放在了 中ArrayList,这会在加载主要活动时强制片段实例化。我需要的是它只是“加载”第一个片段(主),当用户Swype加载另一个片段时。它有什么方法可以实现这一目标?这是我的页面适配器

public class PagerAdapter extends FragmentPagerAdapter  {

    private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
   // private final ArrayList<String> titulos = new ArrayList<String>();

   // private int NUM_PAGES =0;
    public PagerAdapter(FragmentManager manager,int num_pages) {
        super(manager);
     //   this.NUM_PAGES = num_pages;
    }


    public void addFragment(Fragment fragment,String title) {
        mFragments.add(fragment);
            notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        //return NUM_PAGES;
       return mFragments.size();
    }

    @Override
    public Fragment getItem(int position) {
        return mFragments.get(position);

    }

} 

采纳答案by Kjell Zijlemaker

The above method from Sun did not work for me (maybe it does for you), but I thought I would share my edit of his method also. Very good method by the way Sun!

Sun 的上述方法对我不起作用(也许对你有用),但我想我也会分享我对他方法的编辑。很好的方法顺便晒一下!

private boolean _hasLoadedOnce= false; // your boolean field

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


    if (this.isVisible()) {
        // we check that the fragment is becoming visible
        if (isFragmentVisible_ && !_hasLoadedOnce) {
            new NetCheck().execute();
            _hasLoadedOnce = true;
        }
    }
}

回答by Sun

I'm gonna add my solution here since I faced a similar issue. My asynchronous task wasn't loading huge amounts of data, but it prevents unnecessary network calls. Here's what I added in my Fragment:

我将在这里添加我的解决方案,因为我遇到了类似的问题。我的异步任务没有加载大量数据,但它可以防止不必要的网络调用。这是我在片段中添加的内容:

private boolean _hasLoadedOnce= false; // your boolean field

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


    if (this.isVisible()) {
        // we check that the fragment is becoming visible
        if (!isFragmentVisible_ && !_hasLoadedOnce) {
            //run your async task here since the user has just focused on your fragment
            _hasLoadedOnce = true;
        }
    }
}

With the above code, your Fragment will be loaded, but your async task will not run until the user actually scrolls to the Fragment for the first time. Once displayed, your async task will run for the first time automatically. Then you can provide a way to load more data via a button or pull to refresh. The above Fragment was in my ViewPager and seemed to work fine.

使用上面的代码,您的 Fragment 将被加载,但您的异步任务将不会运行,直到用户第一次真正滚动到 Fragment。显示后,您的异步任务将首次自动运行。然后,您可以提供一种通过按钮或下拉刷新来加载更多数据的方法。上面的片段在我的 ViewPager 中,似乎工作正常。

回答by Georgian Benetatos

Use fragmentStatePageAdapter if you have a lot of pages and you want to destroy them when not visible. It has implemented a setMenuVisibility(boolean menuVisible) when fragment becomes visible, so use that.

如果您有很多页面并且想要在不可见时销毁它们,请使用 fragmentStatePageAdapter。当片段变得可见时,它已经实现了一个 setMenuVisibility(boolean menuVisible),所以使用它。

回答by SolidSnake

I might be late for the party but here's my solution and it works as expected. In all of your child fragments create a booleanvariable:

我可能会迟到,但这是我的解决方案,它按预期工作。在您的所有子片段中创建一个boolean变量:

private boolean loadFragmentExecuted = false;

in the child fragments create a generic method called loadFragmentand move all of the logic you added in onCreateViewto that method:

在子片段中创建一个通用方法loadFragment,并将您添加onCreateView到该方法中的所有逻辑移动:

public void loadFragment()
{
    if(!loadFragmentExecuted)
    {
        //Add your logic to manipulate the UI or load data etc...
        loadFragmentExecuted = true;
    }
}

in your pageview logic create the fragments dynamically like:

在您的网页浏览逻辑中,动态创建片段,如:

//add the fragment
String fragmentName = "com.something." + fragmentId;

//check if the class exists
try
{
    Class myFragmentClass = Class.forName(fragmentName);
    Fragment myFragment = (Fragment) myFragmentClass.newInstance();
    mFragments.add(myFragment);
}
catch (ClassNotFoundException e)
{
    e.printStackTrace();
}
catch (IllegalAccessException e)
{
    e.printStackTrace();
}
catch (InstantiationException e)
{
    e.printStackTrace();
}

then set your pager adapter and attach a tablayout with it:

然后设置您的寻呼机适配器并使用它附加一个 tablayout:

//set our pager adapter that contains different fragments
mPagerAdapter = new BasePagerAdapter(mFragmentManager, mFragments);

//link the adapter to the viewpager
mViewPager.setAdapter(mPagerAdapter);

//cache fragments
int limit = (mPagerAdapter.getCount() > 0 ? mPagerAdapter.getCount() : 1);
mViewPager.setOffscreenPageLimit(limit);

//add the page listner to the viewPager and link it to the tabLayout
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));

//on tab selected select current viewpager item
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener()
{
    @Override
    public void onTabSelected(TabLayout.Tab tab)
    {
        mViewPager.setCurrentItem(tab.getPosition());

        //get fragment for the selected tab
        Fragment f = mPagerAdapter.getItem(tab.getPosition());

        //load the content of the fragment
        try
        {
            Class c = f.getClass();
            Method loadFragment = c.getMethod("loadFragment");
            loadFragment.invoke(f);
        }
        catch (IllegalAccessException e){}
        catch (InvocationTargetException e){}
        catch (NoSuchMethodException e){}
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab)
    {
    }

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

回答by pjwin

Slightly modified version to fix potential NPE caused by some views not fully initialised

稍微修改的版本以修复由于某些视图未完全初始化而导致的潜在 NPE

private boolean _hasLoadedOnce= false; // your boolean field

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


    if (this.isVisible()) {
        // we check that the fragment is becoming visible
        if (!isFragmentVisible_ && !_hasLoadedOnce) {
            new Handler().post(() -> {
                makeAsyncRequest();//do your asyn stuffs 
                _hasLoadedOnce = true;
            });
        }
    }
}