【问题标题】:View pager and fragment lifecycle查看寻呼机和片段生命周期
【发布时间】:2014-07-11 12:38:00
【问题描述】:

我有一个一次加载三个页面的 ViewPager。如果我从第 1 页滑到第 2 页,然后滑到第 3 页,则第一页(片段)转到onPause()。然后,如果我滑动到第二页,第一页就会到达onResume(),即使用户仍然看不到第 1 页。所以,我的问题是:如何区分代码中的第一页和第二页?例如,如果我必须在片段可见时运行一段代码,那是怎么做的?

【问题讨论】:

标签: android android-fragments android-viewpager android-lifecycle


【解决方案1】:

FragmentPagerAdapter 将除了显示的片段之外的其他片段保持在恢复状态。解决方案是实现一个自定义的 OnPageChangeListener 并创建一个新的方法来显示片段。

1) 创建 LifecycleManager 接口 该接口将有两个方法,每个 ViewPager 的 Fragment 都会实现它。这些方法如下:

public interface FragmentLifecycle {

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

}

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) 在每个片段中实现接口方法为了检查它是否真的按预期工作,我将记录方法调用并显示 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) ViewPager换页时调用接口方法可以在ViewPager上设置OnPageChangeListener,并在ViewPager每次显示另一页时获取回调:

pager.setOnPageChangeListener(pageChangeListener);

5) 实现 OnPageChangeListener 以调用您的自定义生命周期方法

Listener 知道新的位置,可以在 PagerAdapter 的帮助下调用新 Fragment 上的接口方法。我可以在这里为新片段调用 onResumeFragment(),在当前片段上调用 ​​onPauseFragment()。

我还需要存储当前片段的位置(最初当前位置等于 0),因为我不知道用户是从左到右还是从右到左滚动。看看我在代码中的意思:

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) { }
};

代码不是我写的。完整教程在这里:http://looksok.wordpress.com/2013/11/02/viewpager-with-detailed-fragment-lifecycle-onresumefragment-including-source-code/

【讨论】:

  • getActivity() 在 onResumeFragment 可能会返回 Null(至少在我的情况下)。解决方案可能是通过接口传递上下文(或活动)。例如。 public void onResumeFragment(Activity 活动)
  • 在我的例子中是 'getItem();'返回没有视图的片段。我已经通过使用“instantiateItem”解决了这个问题。 developer.android.com/reference/android/support/v4/view/…, int)
  • 不工作。大多数适配器的getItem(pos) 返回片段的新实例,但我们需要将缓存添加到片段管理器片段中。所以你会在新创建的没有附加到活动实例上调用.onPauseFragment()。不要复制粘贴未经测试的代码。以及为什么它被接受
  • getActivity 返回 null 那是因为 @vigilancer 告诉大多数适配器的 getItem(pos) 返回新实例......如果你缓存不是
  • onPageSelected(currentPosition) 返回的片段将与 WAS 可见的片段不同。这将是一个全新的 Fragment,尚未在其上调用 onCreateView,并且在您返回该位置之前不会调用它。如果您想使用不再可见的 Fragment,请将其缓存,但请确保在不再需要时将其无效。
【解决方案2】:

如果您的 Fragment 扩展了 android.support.v4.app.Fragment

你可以使用它,它对我有用。

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

【讨论】:

  • 第一次创建片段时,在该方法中,getActivity()getContext() 将返回 null。我个人更喜欢onPageSelected() 方法。
  • setUserVisibleHint 现在已弃用。有没有其他选择
【解决方案3】:

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

【讨论】:

  • 默认值为1,表示前一个片段和下一个片段都处于空闲状态。
  • 查看寻呼机一次总是至少加载 3 个页面。我的问题是当其中一个页面可见时如何获得回调。
【解决方案4】:

覆盖setUserVisibleHint()。一旦片段对用户可见,该方法就会调用。

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 第一次创建片段时也会调用
    • 是的..但是如果您在浏览器中有多个片段,该方法将很有用
    • 你只需要测试 (getUserVisibleHint) 因为这个函数返回天气是否可见。确保你在超级方法之后调用它。
    【解决方案6】:

    解决您的问题:

    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;
        }
    }
    

    【讨论】:

      【解决方案7】:

      在片段之间滑动时不会调用片段的生命周期方法。您可以使用ViewPager.SimpleOnPageChangeListener 来解决这个问题。示例代码如下(在 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-28
        • 2016-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-24
        • 1970-01-01
        • 2013-07-12
        相关资源
        最近更新 更多