wake-up-neo.net

verursacht einen Java.IllegalStateException-Fehler, No Activity, nur wenn zum zweiten Mal zu Fragment navigiert

Ich bekomme einen sehr rätselhaften Fehler, von dem ich keine Ahnung habe, wie ich überhaupt damit anfangen soll. 

Ich habe eine einfache App mit einer Aktivität, die Ansichten werden mit Fragments implementiert. Eines der Fragmente enthält einen ViewPager. Daher entschied ich, dass ich die Klasse getChildFragmentManager der v4-Unterstützungsbibliothek verwenden wollte. Ich musste auch ActionBarSherlock verwenden, was zu einem Problem führte, da es nicht mit v11 der v4-Bibliothek geliefert wird. 

Dies wurde behoben, indem die v4-Unterstützungsbibliothek in ABS durch die v11-Bibliothek ersetzt wurde. Alles wurde kompiliert und schien zu funktionieren, einschließlich des ViewPagers. 

Hier ist der seltsame Teil: 

Wenn das Fragment mit dem ViewPager zum ersten Mal geöffnet wird, funktioniert es ordnungsgemäß. Bei der ZWEITEN Navigation stürzt die App ab und es wird eine unbrauchbare Stack-Spur angezeigt. Beim Debuggen habe ich festgestellt, dass das Problem mit dem von getChildFragmentManager zurückgegebenen FragmentManager lag. Es wird der Fehler Keine Aktivität ausgegeben. 

Hat jemand eine Idee, woran das liegen könnte? 

Ich werde Code veröffentlichen, der Ihrer Meinung nach relevant ist. 

Danke, David

35
user1743524

Ich folgte dem Link in jeremyvillalobos answer (was sehr hilfreich war), der mich zu diesem Workaround führte.

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

    ...
}

Es funktioniert gut für mich, ohne dass ich das Fragment wiederherstellen muss.

46
lopisan

Dies scheint ein Fehler zu sein

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

Die Variable 

FragmentManagerImpl mChildFragmentManager;

In Fragment.Java wird beim Trennen nicht auf null gesetzt. Beim nächsten Laden des Fragments zeigt die Variable immer noch auf das letzte übergeordnete Element.

Wie in diesem Thread besprochen, besteht eine Problemumgehung darin, das Fragment wieder herzustellen.

In meinem Fall habe ich in einer ActionBar-Registerkarte zwischen Fragmenten gewechselt. Das gestörte Fragment hat Fragmente verschachtelt und stürzte die App ab, als er zum Dateilader Fragment zurückkehrte. Dies ist also der Umgehungscode:

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

}
23

leider ist es ein fehler der unterstützung v4, immer noch da :(

Wenn Sie ein anderes Fragment über die Navigationsleiste oder ein ähnliches Element auswählen, wird das Fragment, das Teilfragmente enthält, getrennt. Der fragmentManager (getChildFragmentManager ()) dieser Unterfragmente ist daher nicht mehr vorhanden. Während diese Fragmente zurückkehren, ist ein Fehler aufgetreten. Bombe!

Offensichtlich sollte Support v4 mChildFragmentManager in onDetach () bereinigen, was aber nicht der Fall war. Daher müssen wir uns auf uns selbst verlassen. wie die folgenden Codes in dem Fragment, das Unterfragmente hat:

@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();
    }

Alles wird in Ordnung sein, einen schönen Tag :)

4
Kevin Liu

Ich habe das gleiche Problem.

In einer Aktivität habe ich 3 Bouttons, um das Fragment mit transaction.replace (...) zu wechseln.

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

Eines dieser Fragmente enthält eine ViewPage mit einem benutzerdefinierten FragmentPagerAdapter. Daher muss ich getChildFragmentManager () ausführen, um geschachtelte Fragmente zuzulassen.

der Konstruktor ist hier:

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

Ich habe also den gleichen Fehler: Die erste Show dieses Fragments funktioniert, aber wenn ich ein anderes Fragment zeige und auf dieses zurückgreife, erhalte ich diese Ausnahme:

02-26 11: 57: 50.798: D/ACRA (776): Warten auf Toast + Worker beendet. Anwendung beenden? true 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): FATALE AUSNAHME: main 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): Java.lang.IllegalStateException: Nein Aktivität 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): unter Android.support.v4.app.FragmentManagerImpl.moveToState (FragmentManager.Java:1075) .__-2-26 11: 57: 50.798 : E/AndroidRuntime (776): bei Android.support.v4.app.FragmentManagerImpl.moveToState (FragmentManager.Java:1070) 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): bei 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): unter Android.support.v4.app.FragmentManagerImpl.moveToState (FragmentManager.Java:931) .__-2-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): bei Android.support.v4.app.BackStackRecord.run (BackStackRecord.Java:682) 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): bei 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): unter Android.os.Handler.handleCallback (Handler.Java:587) 
 02-26 11: 57: 50.798: E/AndroidRuntime (776) ): bei Android.os.Handler.dispatchMessage (Handler.Java:92) 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): bei Android.os.Looper.loop (Looper.Java:132 ) 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): unter Android.app.ActivityThread.main (ActivityThread.Java:4126) 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): bei Java.lang.reflect.Method.invokeNative (native Methode) 
 02-26 11: 57: 50.798: E/AndroidRuntime (776): bei Java.lang.reflect.Method.invoke (Methode. 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.osyote.it.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: Reaktion auf Signal 3 
 02-26 11: 57: 52.818: I/dalvikvm (776): Schrieb Stack-Spuren nach '/data/anr/traces.txt'

Anstatt die gleiche Instanz von fragment zu setzen, kann ich das also neu erstellen, um das Problem zu beheben, aber ich scheine nicht effizient zu sein.

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

kann Ihr Fehler Android.view.InflateException sein?

wenn ja, sollten Sie Fragment dynamisch aufblasen, verwenden Sie kein XML-Layout.

und Sie sollten kein Fragment anvisieren, das als XML-Layout für Fragment Transaction definiert ist.

2
dmnlk

Antwort von @lopisan:

Ich benutze seine Lösung lange Zeit.

ABER ich finde einen besseren Weg, dies zu tun!

Wenn mChildFragmentManager.mActivity NULL ist, setzen Sie mChildFragmentManager auf NULL. Bei der performActivityCreated-Methode.

@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);
        }
    }
}
0
林奕忠

Ich stecke mit dem gleichen Fehler fest, der BottomNavigationView-Schalter und das Ersetzen eines Fragments verwendet, was zum Absturz der App führt. Bei normaler Geschwindigkeit funktionierte es einwandfrei, wenn der Benutzer den schnellen Wechsel ausführte, stürzte er ab 

IllegalStateException Keine Aktivität

in Protokollen

Bevor ich habe

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

Ich denke, diese Vorerstellung von Fragment und deren Verwendung war zum Ersetzen das Problem, jetzt habe ich es jedes Mal neu erstellt. Es hat gut funktioniert

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

Ich hoffe, es ist hilfreich für einige, ich habe zu viel defensives Programmieren gemacht, aber es wurde mein Problem des schnellen Austauschs von Fragmenten gelöst

0
Sandeep Tengale