Подтвердить что ты не робот

FragmentStatePagerAdapter с ChildFragmentManager - FragmentManagerImpl.getFragment приводит к исключению NullPointerException

РЕДАКТИРОВАТЬ 2

Теперь мне удалось избавиться от ошибки с помощью трюка отсюда https://code.google.com/p/android/issues/detail?id=42601#c10, чтобы reoson, почему было добавлено мое последнее редактирование в дополнение к моему вопросу.

Но это привело к следующей ошибке:

java.lang.NullPointerException
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:569)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1281)
at android.view.View.dispatchRestoreInstanceState(View.java:12043)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2688)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694)
at android.view.View.restoreHierarchyState(View.java:12021)
at android.support.v4.app.Fragment.restoreViewState(Fragment.java:425)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:949)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4800)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
at dalvik.system.NativeStart.main(Native Method)

И теперь я не знаю, где продолжить...

Изменить 0 - ПЕРВЫЙ вопрос

Я получаю следующее исключение:

java.lang.IllegalStateException: No activity
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1091)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1877)
at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1492)
at android.support.v4.app._HoloFragment.performActivityCreated(_HoloFragment.java:251)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4800)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
at dalvik.system.NativeStart.main(Native Method)

Я не знаю, с чего начать. Я использую обновленную библиотеку поддержки (v4, rev18).

Все работает нормально, пока я не добавлю Fragment, который содержит ViewPager в комбинации с FragmentStatePagerAdapter.

Я использую всю библиотеку поддержки, я пробовал решения из https://code.google.com/p/android/issues/detail?id=42601...

Но ничего не получилось...

Я не знаю, с чего начать, кто-нибудь подскажет?

РЕДАКТИРОВАТЬ 1: ПРЕДПОСЫЛКА и код

1) В моей MainActivity я использую следующее:

На третьей странице есть viewpager...

public void setPage(int pos, boolean addToBackStack)
 {
    Fragment nextFragment = null;
    FragmentTransaction transaction = null;

    switch (pos)
    {
        case 0:
            if (mFragmentAllRoutines == null)
                mFragmentAllRoutines = new RoutinesListFragment();
            if (!mFragmentAllRoutines.isVisible())
                nextFragment = mFragmentAllRoutines;
            break;
        case 1:
            if (mFragmentRoutine == null)
                mFragmentRoutine = new RoutineFragment();
            if (!mFragmentRoutine.isVisible())
                nextFragment = mFragmentRoutine;
            break;
        case 2:
            if (mFragmentDay == null)
                mFragmentDay = new RoutineDayFragment();
            if (!mFragmentDay.isVisible())
                nextFragment = mFragmentDay;
            break;
        default:
            break;
    }

    if (nextFragment != null)
    {
        // Fragment prevFragment = getSupportFragmentManager().findFragmentById(R.id.fragment);
        transaction = getSupportFragmentManager().beginTransaction();
        // if (prevFragment != null)
        //    transaction.detach(prevFragment);
        transaction.replace(R.id.fragment, nextFragment, nextFragment.getClass().getName());
        // transaction.attach(nextFragment);
        if (addToBackStack)
            transaction.addToBackStack(null);
        transaction.commit();
    }
}

2) третий фрагмент:

Это простой фрагмент с ViewPager и FragmentStatePagerAdapter. FragmentStatePagerAdapter получает getChildFragmentManager() как FragmentManager. И где-то, похоже, проблема.

4b9b3361

Ответ 1

Мне нужно будет увидеть больше кода, чтобы знать, где его применять... но у меня была аналогичная ситуация, как и вы... Я решил проблему ChildFragmentManager тем же образом и получил тот же NullPointerException, как и у вас.

Мне удалось решить эту проблему... Я попытаюсь описать свое решение, так как с кодом, который вы предоставили, я не уверен, где применять "исправление"... Это действительно исправление... это не элегантный способ решить это! Тем не менее, это помогло мне, и мне не нужно восстанавливать состояния, как только я буду перемещаться в сторону пейджера, поэтому для меня нет недостатка.

У меня есть несколько фрагментов, которые реализуют статический бит кода и onDetach (на https://code.google.com/p/android/issues/detail?id=42601#c10), каждый фрагмент имеет пейджер, а onCreateView - адаптер, расширяющий FragmentStatePagerAdapter.

на этих адаптерах я переопределил метод restoreState, чтобы ничего не делать

    @Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
    //do nothing here! no call to super.restoreState(arg0, arg1);
}

Опять же, это не самый лучший способ... но это решило мою проблему.

Удачи!

Ответ 2

Я только что наткнулся на ту же проблему.

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
     at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:873)
     at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:215)

Решение Marc работает, но в моем случае это вызвало задержки на фрагменте с помощью FragmentStatePagerAdapter. Поэтому я переопределил restoreState, названный super, завернул его в try/catch и работал без лаг.

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
    try{
        super.restoreState(state, loader);
    }catch (NullPointerException e){
        // null caught
    }
}

Ответ 3

На моей стороне я сохранял ссылку на фрагменты ViewPager в содержащем фрагменте и использовал onSaveInstanceState для хранения своих состояний. Я думаю, что NPE произошел потому, что это столкнулось с собственным механизмом ViewPager для восстановления фрагментов. Что я сделал, изменив мою архитектуру из ViewPager, чтобы фрагментировать транзакции, которыми я управляю сам. (ViewPager не было подходящим решением для моего случая)

Ответ 4

Прежде всего, английский не мой родной язык, если у меня что-то не так в грамматике, скажите, пожалуйста. Я столкнулся с этой проблемой в своем проекте. Сначала я сделал то, что сказал Марк, и это сработало хорошо. Но когда я добавил еще один ViewPager в фрагменте отцов, новый ViewPager был таким же, как и старый, независимо от того, какой код в этом новом представлении. Наконец я нашел причину. Мы всегда создаем фрагмент, используя метод FragmentTrasaction.replace(R.layout.fragment, fragment). Из-за этого мы создаем новый экземпляр фрагмента, когда мы используем этот метод. Вместо метода replace() я использую метод FragmentTransaction.hide() и show() для переключения фрагмента. Я решил проблему таким образом. Вот мои фрагменты кода:

@Override
public void onClick(View v) {
    FragmentTransaction transaction = fm.beginTransaction();
    switch (v.getId()) {
        case R.id.tv_schedule_day:
        hideFragment(transaction);
        if (dayFragment == null) {
            dayFragment = new ScheduleDayFragment();
            transaction.add(R.id.ll_schedule_content, dayFragment);
        } else {
            transaction.show(dayFragment);
        }
        transaction.commit();
        break;
        case R.id.tv_schedule_week:
        hideFragment(transaction);
        if (weekFragment == null) {
            weekFragment = new ScheduleWeekFragment();
            transaction.add(R.id.ll_schedule_content, weekFragment);
        } else {
            transaction.show(weekFragment);
        }
        transaction.commit();
        break;
    case R.id.tv_schedule_month:
        hideFragment(transaction);
        if (monthFragment == null) {
            monthFragment = new ScheduleMonthFragment();
            transaction.add(R.id.ll_schedule_content, monthFragment);
        } else {
            transaction.show(monthFragment);
        }
        transaction.commit();
        break;

private void hideFragment(FragmentTransaction transaction) {
    if (dayFragment != null) {
        transaction.hide(dayFragment);
    }
    if (weekFragment != null) {
        transaction.hide(weekFragment);
    }
    if (monthFragment != null) {
        transaction.hide(monthFragment);
    }
}

Я использую методы hide() и show() для создания фрагмента отключателя, поэтому, когда я использую getChildFragmentManager() во встроенном фрагменте, он не возвращает null. Этот вопрос был задан в 2013 году, я думаю, что никто не увидит этого ответа, но я все еще очень рад ответить на этот вопрос.