简体   繁体   English

查看寻呼机和片段生命周期

[英]View pager and fragment lifecycle

I have a ViewPager that loads three pages at a time.我有一个一次加载三个页面的 ViewPager。 If I swipe from page 1 to page 2 then to 3, the first page(fragment) goes to onPause() .如果我从第 1 页滑动到第 2 页,然后再滑动到第 3 页,则第一页(片段)将转到onPause() Then, if I swipe to the second page, 1st page comes to onResume() even though the page 1 is still not visible to the user.然后,如果我滑动到第二页,即使第 1 页对用户仍然不可见,第 1 页也会进入onResume() So, my question is: how to distinguish between the first and second page in code?所以,我的问题是:如何区分代码中的第一页和第二页? For example, if I have to run a piece of code when the fragment is visible, how is that done?例如,如果我必须在片段可见时运行一段代码,这是如何完成的?

The FragmentPagerAdapter keeps additional fragments, besides the one shown, in resumed state. FragmentPagerAdapter 将其他片段(除了显示的片段)保持在恢复状态。 The solution is to implement a custom OnPageChangeListener and create a new method for when the fragment is shown.解决方案是实现自定义 OnPageChangeListener 并在显示片段时创建一个新方法。

1) Create LifecycleManager Interface The interface will have two methods and each ViewPager's Fragment will implement it. 1) 创建 LifecycleManager 接口 该接口有两个方法,每个 ViewPager 的 Fragment 都会实现它。 These methods Are as follows:这些方法如下:

public interface FragmentLifecycle {

    public void onPauseFragment();
    public void onResumeFragment();

}

2) Let each Fragment implement the interface Add iplements statement for each class declaration: 2)让每个Fragment实现接口为每个类声明添加iplements语句:

public class FragmentBlue extends Fragment implements FragmentLifecycle
public class FragmentGreen extends Fragment implements FragmentLifecycle
public class FragmentPink extends Fragment implements FragmentLifecycle

3) Implement interface methods in each fragment In order to check that it really works as expected, I will just log the method call and show Toast: 3) 在每个片段中实现接口方法为了检查它是否真的按预期工作,我将记录方法调用并显示 Toast:

@Override
public void onPauseFragment() {
    Log.i(TAG, "onPauseFragment()");
    Toast.makeText(getActivity(), "onPauseFragment():" + TAG, Toast.LENGTH_SHORT).show(); 
}

@Override
public void onResumeFragment() {
    Log.i(TAG, "onResumeFragment()");
    Toast.makeText(getActivity(), "onResumeFragment():" + TAG, Toast.LENGTH_SHORT).show(); 
}

4) Call interface methods on ViewPager page change You can set OnPageChangeListener on ViewPager and get callback each time when ViewPager shows another page: 4)ViewPager页面变化时调用接口方法可以在ViewPager上设置OnPageChangeListener,每次ViewPager显示另一个页面时获取回调:

pager.setOnPageChangeListener(pageChangeListener);

5) Implement OnPageChangeListener to call your custom Lifecycle methods 5) 实现 OnPageChangeListener 来调用你自定义的 Lifecycle 方法

Listener knows the new position and can call the interface method on new Fragment with the help of PagerAdapter. Listener 知道新的位置,可以在 PagerAdapter 的帮助下调用新 Fragment 上的接口方法。 I can here call onResumeFragment() for new fragment and onPauseFragment() on the current one.我可以在这里为新片段调用 onResumeFragment() 并在当前片段上调用 ​​onPauseFragment() 。

I need to store also the current fragment's position (initially the current position is equal to 0), since I don't know whether the user scrolled from left to right or from right to left.我还需要存储当前片段的位置(最初当前位置等于 0),因为我不知道用户是从左向右滚动还是从右向左滚动。 See what I mean in code:看看我在代码中的意思:

private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {

    int currentPosition = 0;

    @Override
    public void onPageSelected(int newPosition) {

        FragmentLifecycle fragmentToShow = (FragmentLifecycle)pageAdapter.getItem(newPosition);
        fragmentToShow.onResumeFragment();

        FragmentLifecycle fragmentToHide = (FragmentLifecycle)pageAdapter.getItem(currentPosition);
        fragmentToHide.onPauseFragment();

        currentPosition = newPosition;
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) { }

    public void onPageScrollStateChanged(int arg0) { }
};

I didn't write the code.我没有写代码。 Full tutorial here: http://looksok.wordpress.com/2013/11/02/viewpager-with-detailed-fragment-lifecycle-onresumefragment-including-source-code/完整教程在这里: http : //looksok.wordpress.com/2013/11/02/viewpager-with-detailed-fragment-lifecycle-onresumefragment-include-source-code/

if your Fragment extend android.support.v4.app.Fragment如果您的 Fragment 扩展 android.support.v4.app.Fragment

you can use this, it works for me.你可以用这个,它对我有用。

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (!isVisibleToUser) {
        //do sth..
    }
}

用户方法 pager.setOffscreenPageLimit(numbr) 设置要在堆栈中保留多少个片段。

Override setUserVisibleHint() .覆盖setUserVisibleHint() This method will call once the fragment is visible to the user.一旦片段对用户可见,此方法将调用。

覆盖setUserVisibleHint()这将在片段对用户可见时调用

Solve your problem:解决您的问题:

public class FragmentVisibleHelper implements LifecycleObserver {

    private static final String TAG = "VipVisibleHelper";

    public interface IVisibleListener {

        void onVisible();

        void onInVisible();
    }

    boolean mIsVisibleToUser;
    boolean mStarted = false;

    volatile boolean mIsCalledVisible = false;
    volatile boolean mIsCalledInvisible = false;


    IVisibleListener mListener;

    public void setListener(IVisibleListener mListener) {
        this.mListener = mListener;
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void onResume() {
        Log.d(TAG, String.format("%-60s %s", this.toString(), "onResume() called:"));
        if (mIsVisibleToUser) {
            dispatchVisible();
        }
    }

    private void dispatchVisible() {
        Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchVisible() called mIsCalledVisible = [" + mIsCalledVisible + "] mIsCalledInvisible = [" + mIsCalledInvisible + "] "));
        if (!mIsCalledVisible) {
            mIsCalledVisible = true;
            mIsCalledInvisible = false;

            if (Profile.LOG) {
                Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchVisible() called onVisible"));
            }

            if (mListener != null) {
                mListener.onVisible();
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    void onPause() {
        Log.d(TAG, String.format("%-60s %s", this.toString(), "onPause() called:"));
        if (mIsVisibleToUser) {
            dispatchInvisible();
        }
    }

    private void dispatchInvisible() {
        Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchInvisible() called mIsCalledVisible = [" + mIsCalledVisible + "] mIsCalledInvisible = [" + mIsCalledInvisible + "] "));
        if (!mIsCalledInvisible) {
            mIsCalledInvisible = true;
            mIsCalledVisible = false;

            if (Profile.LOG) {
                Log.d(TAG, String.format("%-60s %s", this.toString(), "dispatchInvisible() called onInVisible"));
            }

            if (mListener != null) {
                mListener.onInVisible();
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStart() {
        Log.d(TAG, String.format("%-60s %s", this.toString(), "onStart() called"));
        mStarted = true;
        if (mIsVisibleToUser) {
            dispatchVisible();
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop() {
        Log.d(TAG, String.format("%-60s %s", this.toString(), "onStop() called"));
        if (mIsVisibleToUser) {
            dispatchInvisible();
        }
        mStarted = false;
    }

    public void setUserVisibleHint(boolean isVisibleToUser) {
        Log.d(TAG, String.format("%-60s %s", this.toString(), "setUserVisibleHint() called with: isVisibleToUser = [" + isVisibleToUser + "]:"));
        mIsVisibleToUser = isVisibleToUser;
        if (mStarted) { // fragment have created
            if (mIsVisibleToUser) {
                dispatchVisible();
            } else {
                dispatchInvisible();
            }
        }
    }

    public boolean isVisibleToUser() {
        return mIsVisibleToUser;
    }
}

The fragment's lifecycle methods are not called when swiping between fragments.在片段之间滑动时不会调用片段的生命周期方法。 You can use ViewPager.SimpleOnPageChangeListener to solve this problem.您可以使用ViewPager.SimpleOnPageChangeListener来解决这个问题。 The sample code is as bellow (in Kotlin).示例代码如下(在 Kotlin 中)。

// other code
mViewPager.addOnPageChangeListener(object: ViewPager.SimpleOnPageChangeListener() {
    override fun onPageSelected(position: Int) {
        val oldPosition = mViewPager.currentItem
        val oldFragment = mViewPager.adapter?.instantiateItem(mViewPager, oldPosition)
        oldFragment.onPauseStuff() // Hint: do as here call onPause
        val newFragment = mViewPager.adapter?.instantiateItem(mViewPager, position)
        newFragment.onResumeStuff() // Hint: do as here call onResume
}
// other code

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM