Вызывая ошибку java.IllegalStateException, No Activity, только при навигации по фрагменту для SECOND time

Я получаю очень загадочную ошибку, о которой я понятия не имею, как начать работу.

У меня есть простое приложение с одним действием, представления реализованы с помощью фрагментов. Один из фрагментов имеет ViewPager внутри него; поэтому я решил, что хочу использовать класс getChildFragmentManager библиотеки поддержки v4. Мне также пришлось использовать ActionBarSherlock, что вызвало проблему, потому что оно не поставляется с v11 библиотеки v4.

Я исправил это, заменив библиотеку поддержки v4 в АБС библиотекой v11, и все было скомпилировано и, казалось, работало, включая ViewPager.

Вот странная часть:

При первом открытии фрагмента с ViewPager он работает правильно; но во второе время, к которому он подключен, приложение выходит из строя, давая бесполезную трассировку стека. От отладки я обнаружил, что проблема связана с FragmentManager, возвращаемым getChildFragmentManager; он выдает ошибку "Нет активности".

Кто-нибудь знает, что может быть причиной этого?

Я отправлю код, который, по вашему мнению, имеет значение.

Спасибо, Дэвид

Ответ 1

Я следил за ссылкой в ​​jeremyvillalobos answer (что было очень полезно), что привело меня к это обходное решение.

public class CustomFragment extends Fragment {
    private static final Field sChildFragmentManagerField;

    static {
        Field f = null;
        try {
            f = Fragment.class.getDeclaredField("mChildFragmentManager");
            f.setAccessible(true);
        } catch (NoSuchFieldException e) {
            Log.e(LOGTAG, "Error getting mChildFragmentManager field", e);
        }
        sChildFragmentManagerField = f;
    }

    @Override
    public void onDetach() {
        super.onDetach();

        if (sChildFragmentManagerField != null) {
            try {
                sChildFragmentManagerField.set(this, null);
            } catch (Exception e) {
                Log.e(LOGTAG, "Error setting mChildFragmentManager field", e);
            }
        }
    }

    ...
}

Он работает для меня хорошо, без необходимости повторного использования фрагмента.

Ответ 2

Это, по-видимому, ошибка, указанная в

https://code.google.com/p/android/issues/detail?id=42601

Переменная

FragmentManagerImpl mChildFragmentManager;

В Fragment.java не установлено значение null при отсоединении. Таким образом, в следующий раз, когда фрагмент загружен, переменная по-прежнему указывает на последнего родителя.

Как обсуждалось в этом потоке, обходной путь заключается в том, чтобы восстановить Фрагмент.

В моем случае я переключался между фрагментами на вкладке ActionBar. Проблемный фрагмент имеет вложенные фрагменты и сбой приложения, возвращаясь к файловому загрузчику Fragment. Итак, это код обхода:

class MainTabsListener implements ActionBar.TabListener {
    public Fragment fragment;
    public int TabPosition;

    public MainTabsListener(Fragment fragment, int tab_position) {
        this.fragment = fragment;
        TabPosition = tab_position;
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        CurrentFragment = fragment;
        CurrentTabSelectedPos = TabPosition;

        /**
         * This is a work-around for Issue 42601
         * https://code.google.com/p/android/issues/detail?id=42601
         * 
         * The method getChildFragmentManager() does not clear up
         * when the Fragment is detached.
         */
        if( fragment instanceof FileLoaderFragment ){
            fragment = reinstatiateFileLoaderFragment();
        }

        ft.replace(R.id.fragment_container, fragment);

    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.remove(fragment);
    }

}

Ответ 3

может возникнуть ваша ошибка android.view.InflateException?

если это так, вы должны динамически раздувать фрагмент, не используйте XML-макет.

и вы не должны использовать целевой фрагмент, который определяется XML-макет для транзакции фрагментации.

Ответ 4

У меня та же проблема.

В действии у меня есть 3 кнопки для переключения фрагмента с помощью transaction.replace(...)

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.layout_tablet_paneau, mLigneMessageFragment);

Один из этих фрагментов содержит ViewPage с пользовательским FragmentPagerAdapter. Поэтому я должен сделать getChildFragmentManager(), чтобы охарактеризовать вложенные фрагменты.

здесь находится конструктор:

public LignePagerAdapter(Fragment ligneMessageTabletFragment) {
        super(ligneMessageTabletFragment.getChildFragmentManager());
    }

Итак, у меня такая же ошибка: первая демонстрация этого фрагмента нарушает, но когда я показываю другой фрагмент и возвращаюсь к этому, я получаю это исключение:

02-26 11:57:50.798: D/ACRA(776): Wait for Toast + worker ended. Kill Application ? true
02-26 11:57:50.798: E/AndroidRuntime(776): FATAL EXCEPTION: main
02-26 11:57:50.798: E/AndroidRuntime(776): java.lang.IllegalStateException: No activity
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1075)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1861)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1474)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:931)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.os.Handler.handleCallback(Handler.java:587)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.os.Handler.dispatchMessage(Handler.java:92)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.os.Looper.loop(Looper.java:132)
02-26 11:57:50.798: E/AndroidRuntime(776):  at android.app.ActivityThread.main(ActivityThread.java:4126)
02-26 11:57:50.798: E/AndroidRuntime(776):  at java.lang.reflect.Method.invokeNative(Native Method)
02-26 11:57:50.798: E/AndroidRuntime(776):  at java.lang.reflect.Method.invoke(Method.java:491)
02-26 11:57:50.798: E/AndroidRuntime(776):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
02-26 11:57:50.798: E/AndroidRuntime(776):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
02-26 11:57:50.798: E/AndroidRuntime(776):  at dalvik.system.NativeStart.main(Native Method)
02-26 11:57:52.818: I/dalvikvm(776): threadid=4: reacting to signal 3
02-26 11:57:52.818: I/dalvikvm(776): Wrote stack traces to '/data/anr/traces.txt'

Итак, вместо того, чтобы помещать один и тот же экземпляр фрагмента, я могу воссоздать его, чтобы он исправить проблему, но я выгляжу неэффективно.

transaction.replace(R.id.layout_tablet_paneau, LigneMessageTabletFragment.newInstance());

Ответ 5

К сожалению, это ошибка поддержки v4, все еще там: (

Когда вы выбираете другой фрагмент через навигационный ящик или другую вещь, подобную ему, фрагмент, который имеет суб-фрагменты, отделяется. Таким образом, фрагментарный фрагмент фрагментов (getChildFragmentManager()) больше не существует. в то время как эти фрагменты возвращаются, произошла ошибка. Бомба!

Очевидно, что поддержка v4 должна очищать mChildFragmentManager в onDetach(), но это не так, поэтому мы должны зависеть от нас самих. таких как следующие коды в фрагменте, который имеет суб-фрагменты:

@Override
    public void onDetach() {
        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        super.onDetach();
    }

Все будет хорошо, у вас будет хороший день:)

Ответ 6

Обратитесь к комментарию @lopisan:

Я использую его решение в течение длительного времени.

НО У меня есть лучший способ сделать это!

Если mChildFragmentManager.mActivity имеет значение NULL, установите для параметра mChildFragmentManager значение null. Когда метод performActivityCreated.

@Override
void performActivityCreated(Bundle savedInstanceState) {
    if (getFragmentManagerActivity(mChildFragmentManager) == null) {
        setChildFragmentManager(this, null);
    }
    super.performActivityCreated(savedInstanceState);
}


public static FragmentActivity getFragmentManagerActivity(FragmentManager fragmentManager) {
    FragmentManagerImpl fm = (FragmentManagerImpl) fragmentManager;
    return fm.mActivity;
}



private static final Field sChildFragmentManagerField;
static {
    /**
     * BUG : causing a java.IllegalStateException error, No Activity, only
     * when navigating to Fragment for the SECOND time
     * http://stackoverflow.com /questions/15207305/getting-the-error-java-lang-illegalstateexception-activity-has-been-destroyed
     * http://stackoverflow.com/questions/14929907/causing-a-java-illegalstateexception-error-no-activity-only-when-navigating-to
     */
    Field f = null;
    try {
        f = Fragment.class.getDeclaredField("mChildFragmentManager");
        f.setAccessible(true);
    } catch (NoSuchFieldException e) {
        Log.e(TAG, "Error getting mChildFragmentManager field", e);
    }
    sChildFragmentManagerField = f;
}

public static void setChildFragmentManager(Fragment fragment, FragmentManager fragmentManager) {
    if (sChildFragmentManagerField != null) {
        try {
            sChildFragmentManagerField.set(fragment, fragmentManager);
        } catch (Exception e) {
            Log.e(TAG, "Error setting mChildFragmentManager field", e);
        }
    }
}

Ответ 7

Я застрял с той же ошибкой, используя переключатель BottomNavigationView и замену фрагмента, вызывающего крах приложения. С нормальной скоростью он работал отлично, если пользователь быстро переключил его, чтобы сбой сказать

IllegalStateException Нет действий

в журналах

Прежде чем у меня

fragmentA = new FragmentA();
fragmentB = new FragmentB();
fragmentC = new FragmentC();

mBottomNavigationView.setOnNavigationItemSelectedListener(item -> {
        switch (item.getItemId()) {
   case R.id.fragmentA:
         replaceFragment(fragmentA);
   case R.id.fragmentB:
        repalceFragment(fragmentB);
   case R.id.fragmentC:
        repalceFragment(fragmentC);
   }
};

Я думаю, что это предварительное создание фрагмента и использование их для замены - это создание проблемы, теперь я сделал это для повторного создания каждый раз. Он начал нормально работать

mBottomNavigationView.setOnNavigationItemSelectedListener(item -> {
        switch (item.getItemId()) {
   case R.id.fragmentA:
        fragment = new FragmentA();
         replaceFragment(fragment);
   case R.id.fragmentB:
        fragment = new FragmentB();
        repalceFragment(fragment);
   case R.id.fragmentC:
        fragment = new FragmentC();
        repalceFragment(fragment);
   }
};

 public void repalceFragment(Fragment fragment) {
    if (!this.isFinishing()) {
        if (!fragment.isAdded()) {
            if (!this.mDisplayedFragment.isRemoving()) {
                getFragmentManager().beginTransaction().replace(R.id.layout_fragment_container, fragment).commit();
                this.mDisplayedFragment = fragment;
            }
        }
    }
}

Надеюсь, что это полезно для некоторых, я сделал слишком много защитного кодирования, но решил мою проблему быстрого переключения фрагментов

Ответ 8

Пожалуйста, проверьте номер 32 этой ссылки:

Child FragmentManager, сохраненный после отсоединения родительского фрагмента

Шаги: