web-dev-qa-db-de.com

Warum scheitert Android O mit "gehört nicht zu diesem FragmentManager!"

Ich habe meine Anwendung zu Android O in Android Studio 3 migriert

Auf einem Android-O-Emulator ausgeführt, schlagen alle meine DialogFragmente jetzt fehl mit: -

Java.lang.IllegalStateException: Fragment MyDialogFragment{43ccf50 #2 MyDialogFragment} declared target fragment SettingsFragment{ceed549 #0 id=0x7f0f0142 Android:switcher:2131689794:0} that does not belong to this FragmentManager!
at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1316)
at Android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.Java:1624)
at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1689)
at Android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.Java:794)
at Android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.Java:2470)
at Android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.Java:2260)
at Android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.Java:2213)
at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:2122)
at Android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.Java:746)
at Android.os.Handler.handleCallback(Handler.Java:769)
at Android.os.Handler.dispatchMessage(Handler.Java:98)
at Android.os.Looper.loop(Looper.Java:164)
at Android.app.ActivityThread.main(ActivityThread.Java:6535)
at Java.lang.reflect.Method.invoke(Native Method)
at com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767)

Ich habe keinerlei Codeänderungen vorgenommen.

Was hat sich in Android O geändert, dass bisher funktionierende DialogFragments jetzt nicht mehr angezeigt werden?

Android Studio 3.0 Canary 1
Build #AI-171.4010489, built on May 15, 2017
JRE: 1.8.0_112-release-b736 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Mac OS X 10.11.6

    compileSdkVersion 'Android-O'
    buildToolsVersion "26.0.0-rc2"

   AndroidManifest.xml
    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 'O'
        }

compile 'com.Android.support:appcompat-v7:26.0.0-beta1'
compile 'com.Android.support:cardview-v7:26.0.0-beta1'
compile 'com.Android.support:design:26.0.0-beta1'
    compile 'com.Android.support:percent:26.0.0-beta1'

  dependencies {
        classpath 'com.Android.tools.build:gradle:3.0.0-alpha1'

    }
26
Hector

Ich hatte das gleiche Problem, definitiv einen Android-Fehler. Dies geschieht, wenn Sie ein Fragment aus einem anderen Fragment als Ziel anzeigen. Als Workaround können Sie Folgendes verwenden:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    getActivity().getFragmentManager().beginTransaction().add(dialogFrag, "dialog").commit();
else
    getChildFragmentManager().beginTransaction().add(dialogFrag,"dialog").commit();
16
greywolf82

Für mich war dies nicht nur ein Problem mit Android O, sondern auch mit älteren Versionen .. Die älteste Version, die ich getestet habe, war API Level 16.

Ich habe meine Fragmente mit diesem Code instanziiert:

MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getActivity().getSupportFragmentManager(), null);

Wenn ParentFragment.this eine benutzerdefinierte Klasse ist, die Android.support.v4.app.Fragment erweitert, erweitert MyFragment auch diese Klasse und ist ein untergeordnetes Fragment des ParentFragment-Fragments (daher der Name).

Ich dachte, ich müsste einen SupportFragmentManager (die getSupportFragmentManager()-Methode) verwenden, da ich ein Fragment des Support-Pakets verwende. Daher habe ich versucht, getActivity().getSupportFragmentManager() aufzurufen, um eine Aktivitätsreferenz zu erhalten, die diese Methode unterstützt.

Dies scheint jedoch nicht der richtige Weg zu sein ... Ich habe diese Aufrufe geändert in:

MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getFragmentManager(), null);

das Fragment entscheidet also selbst, welches FragmentManager verwendet werden soll, und der Fehler ist jetzt verschwunden.

Hoffe das hilft jemandem.

50
Markus Ressel

Ich hatte gerade die gleichen Probleme in dem Projekt, an denen ich gerade arbeite, als wir zu Android Studio 3 wechselten und die Support-Bibliothek auf Version 26 aufrüsten. Plötzlich haben wir, ohne den Code zu ändern, eine Unmenge dieser Ausnahme. Am Ende habe ich folgendes herausgefunden:

Google hat im Januar dieses Jahres eine neue "Sanitätsprüfung" in den Quellen des v4 Fragment Manager hinzugefügt (nicht sicher, in welcher Version er sich befand), die es ablehnt, ein Fragment mithilfe eines Fragment Managers hinzuzufügen, wenn ein Zielfragment und das Ziel festgelegt sind Fragment kann nicht in den aktiven Fragmenten desselben Fragment-Managers gefunden werden. Der Patch wird ausführlich beschrieben hier

Ealier-Versionen scheinen sich nicht darum gekümmert zu haben. Ich habe einige Tage gebraucht, um alle Bereiche in unserem Code zu aktualisieren, in denen Fragmente, die mit dem Support Fragment Manager hinzugefügt wurden, den Child Fragment Manager für ihre Unterfragmente mit dem übergeordneten Fragment als Ziel verwendet haben. Nun, späte Strafe für das Schreiben von schlechtem Code.

6
Nantoka

Ich hatte den gleichen Fall wie Markus Ressel, verwendete aber getChildFragmentManager (). Ich habe das durch getFragmentManager () ersetzt und das Problem wurde behoben. 

UPDATE: Ich arbeite jetzt mit childFragmentManager und habe etwas Feedback. 

Beim Umgang mit inneren Fragmenten, die von einem Fragment gehostet werden (also einem Fragment innerhalb eines Fragments), verwenden Sie den childFragmentManager. Dieser Fragmentmanager unterscheidet sich von den Aktivitäten getSupportFragmentManager. Die beiden sind nicht gleich. Es ist eine Trennung der Sorgen. 

Ich habe also die Regel aufgestellt, dass Fragmente, die untergeordnete Fragmente hosten, immer den childFragmentManager verwenden. 

5
j2emanue

meine App funktioniert gut, bis die Zielversion auf 27 aufgerüstet ist. Dann sehe ich dasselbe Problem, wenn Sie setTargetFragment (Fragmentfragment, int requestCode) aufrufen. _

beispiel: 

chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION); 

ändern Sie einfach zu: 

chooseRegionFragment.setTargetFragment(getRootParentFragment(this), REQUEST_CODE_CHOOSE_REGION);

getRootParentFragment(this) Diese Methode findet das Stammeltern der Fragmente für Sie

/** 
   * find root parent of fragment 
   */ 
  public static Fragment getRootParentFragment(Fragment fragment) { 
    Fragment parent = fragment.getParentFragment(); 
    if(parent == null) 
      return fragment; 
    else 
      return getRootParentFragment(parent); 
  } 
1
vuhung3990

Verwenden Sie die untenstehende Lösung, und Sie müssen sich keine Gedanken darüber machen, mit welchen Fragmentmanagern Sie sich befassen.

Vorausgesetzt, Sie müssen ein BaseFragment verwendet haben.

Erstellen Sie zuerst eine Schnittstelle:

public interface OnRequestUpdateListener {
void onRequestUpdate(final int requestCode, final Intent data);

void setRequestFragment(final BaseFragment requestFragment, int requestCode);

BaseFragment getRequestFragment();

int getRequestCode();

}

Implementieren Sie diese Schnittstelle in Ihrem BaseFragment

public class BaseFragment extends Fragment implements OnRequestUpdateListener {
private BaseFragment requestFragment;

private int requestCode;

@Override
public void onRequestUpdate(int requestCode, Intent data) {
 // you can implement your logic the same way you do in onActivityResult
}

@Override
public void setRequestFragment(BaseFragment requestFragment, int requestCode) {
    this.requestFragment = requestFragment;
    this.requestCode = requestCode;
}

@Override
public BaseFragment getRequestFragment() {
    return requestFragment;
}

@Override
public int getRequestCode() {
    return requestCode;
}

}

Ersetzen Sie dann setTargetFragment durch setRequestFragment und ersetzen Sie getTargetFragment durch getRequestFragment. 

Hier könnten Sie auch onRequestUpdate anstelle von onActivityResult verwenden.

Dies ist eine benutzerdefinierte Lösung, ohne sich darum zu kümmern, welchen Fragment-Manager Sie verwenden.

Die Verwendung von getFragmentManager () anstelle von getChildFragmentManager () würde ebenfalls funktionieren, hat jedoch Auswirkungen auf getParentFragment (). Wenn Sie für verschachteltes Fragment kein getChildFragmentManager () verwenden, können Sie das übergeordnete Fragment nicht abrufen, indem Sie getParentFragment () im untergeordneten/verschachtelten Fragment verwenden.

0
Rikin Prajapati

Vor kurzem gab es bei meiner App dasselbe Problem, als ich sie für Android O anvisierte. Als Lösung verwenden Sie: 

myDialogFragment.show(SettingsFragment.this.getFragmentManager(), TAG);

anstatt:

myDialogFragment.show(getFragmentManager(), TAG);
// or  
myDialogFragment.show(getSupportFragmentManager(), TAG);
// or  
myDialogFragment.show(getChildFragmentManager(), TAG);
0
eyeslave