Посмотреть пейджер и фрагмент жизненного цикла
У меня есть ViewPager, который загружает три страницы одновременно. Если я проведу пальцем со страницы 1 на страницу 2, затем на 3, первая страница (фрагмент) перейдет к onPause()
, Затем, если я проведу по второй странице, onResume()
хотя страница 1 все еще не видна пользователю. Итак, мой вопрос: как отличить первую и вторую страницу в коде? Например, если мне нужно запустить фрагмент кода, когда фрагмент виден, как это сделать?
8 ответов
FragmentPagerAdapter хранит дополнительные фрагменты, кроме показанного, в возобновленном состоянии. Решение состоит в том, чтобы реализовать пользовательский OnPageChangeListener и создать новый метод для отображения фрагмента.
1) Создание интерфейса LifecycleManager Интерфейс будет иметь два метода, и каждый фрагмент ViewPager будет реализовывать его. Эти методы заключаются в следующем:
public interface FragmentLifecycle {
public void onPauseFragment();
public void onResumeFragment();
}
2) Пусть каждый Fragment реализует интерфейс Add 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. Вы можете установить OnPageChangeListener для ViewPager и получать обратный вызов каждый раз, когда ViewPager показывает другую страницу:
pager.setOnPageChangeListener(pageChangeListener);
5) Реализуйте OnPageChangeListener для вызова ваших пользовательских методов жизненного цикла
Слушатель знает новую позицию и может вызвать интерфейсный метод для нового фрагмента с помощью PagerAdapter. Здесь я могу вызвать 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/
Если ваш фрагмент расширяется android.support.v4.app.Fragment
Вы можете использовать это, это работает для меня.
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (!isVisibleToUser) {
//do sth..
}
}
Пользовательский метод pager.setOffscreenPageLimit(numbr), чтобы установить, сколько фрагментов вы хотите сохранить в стеке.
Override setUserVisibleHint()
, Этот метод будет вызываться, как только фрагмент будет виден пользователю.
Переопределить setUserVisibleHint() это вызовет, когда фрагмент виден пользователю
Методы жизненного цикла фрагмента не вызываются при перелистывании между фрагментами. Вы можете использоватьViewPager.SimpleOnPageChangeListener
чтобы решить эту проблему. Пример кода показан ниже (в Котлине).
// 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
Решите вашу проблему:
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;
}
}
Внутри адаптера пейджера вы можете поместить этот метод.
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Fragment fragment = fragments.get(position);
if (fragment == null) {
fragment = (Fragment) super.instantiateItem(container, position);
fragments.put(position, fragment);
}
return fragment;
}
public Fragment getFragment(int position) {
return fragments.get(position);
}
Затем внутри прослушивателя смены страницы вы можете получить текущий фрагмент и запустить свой метод внутри своего фрагмента.
currentFragment = adapter.getFragment(viewPager.getCurrentItem());
((DetailNewsFragment)currentFragment).runYourMethod();
Специально не используйте adapter.getItem(position) . потому что он возвращает новый экземпляр фрагмента.