为什么Android O会因“失败”而失败;不属于此碎片管理器&引用;

为什么Android O会因“失败”而失败;不属于此碎片管理器&引用;,android,android-dialogfragment,android-8.0-oreo,Android,Android Dialogfragment,Android 8.0 Oreo,我已经将我的应用程序迁移到Android Studio 3中的Android O 在Android O emulator上运行时,我的所有DialogFragment现在都会失败,原因是:- java.lang.IllegalStateException: Fragment MyDialogFragment{43ccf50 #2 MyDialogFragment} declared target fragment SettingsFragment{ceed549 #0 id=0x7f0f0142

我已经将我的应用程序迁移到Android Studio 3中的Android O

在Android O emulator上运行时,我的所有DialogFragment现在都会失败,原因是:-

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)
我没有做任何代码更改

安卓O中发生了什么变化,以前工作的DialogFragments现在无法显示

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'

    }

我也有同样的问题,肯定是安卓的错误。当您使用另一个片段作为目标显示该片段时,就会发生这种情况。作为解决方法,您可以使用:

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

对我来说,这不仅是安卓O上的一个问题,也是旧版本上的一个问题。 我测试的最旧版本是API级别16

我正在使用以下代码实例化我的片段:

MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getActivity().getSupportFragmentManager(), null);
其中
ParentFragment.this
是一个自定义类,扩展了
android.support.v4.app.Fragment
MyFragment
也扩展了这个类,是
ParentFragment
片段的子片段(因此它的名字)

我认为我必须使用SupportFragmentManager(方法
getSupportFragmentManager()
),因为我使用的是支持包的一个片段,所以我尝试调用
getActivity().getSupportFragmentManager()
,以获取支持此方法的活动引用

但这似乎不是正确的方法。 我将这些电话改为:

MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getFragmentManager(), null);
因此,片段自行决定使用哪个FragmentManager,错误现在消失了


希望这对某人有所帮助。

我的案例与Markus Rescel相同,但我使用的是getChildFragmentManager()。我用getFragmentManager()替换了它,它解决了这个问题

更新:我现在一直在与childFragmentManager合作,并有一些反馈

当处理由片段承载的内部片段(因此片段中的片段)时,请使用childFragmentManager。此片段管理器不同于活动getSupportFragmentManager。这两者不一样。这是关注点的分离


因此,我制定了一条规则,托管子片段的片段将始终使用childFragmentManager,而不在主机片段内的内容可以使用getSupportfragmentManager

当我们搬到Android Studio 3并将支持库升级到版本26时,我正在处理的项目中遇到了相同的问题。突然,在不改变代码的情况下,我们得到了大量的异常。最后我发现了以下几点:

今年1月,谷歌在v4片段管理器的源代码中添加了一个新的“健全性检查”(不确定发布到哪个版本),拒绝使用片段管理器添加片段,如果它设置了目标片段,并且在同一片段管理器的活动片段中找不到目标片段。详细描述了补丁程序


早期的版本似乎并不关心这一点。我花了几天时间更新代码中的所有区域,其中使用支持片段管理器添加的片段将子片段管理器用于其子片段,父片段作为目标。好吧,迟写错误代码的惩罚。

我的应用程序运行良好,直到将目标版本升级到27,然后我在打电话时面临同样的问题

例如:

chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION); 
只需更改为:

chooseRegionFragment.setTargetFragment(getRootParentFragment(this), REQUEST_CODE_CHOOSE_REGION);
getRootParentFragment(this)
此方法将为您找到片段的根父级

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

最近,我的应用程序在针对Android O时遇到了同样的问题。作为解决方案,请使用:

myDialogFragment.show(SettingsFragment.this.getFragmentManager(), TAG);
而不是:

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

使用下面的解决方案,您就不必担心您要处理的是哪个片段管理器

假设您一定使用了BaseFragment

首先创建一个接口:

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

void setRequestFragment(final BaseFragment requestFragment, int requestCode);

BaseFragment getRequestFragment();

int getRequestCode();
}

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

然后,用setRequestFragment替换setTargetFragment,用getRequestFragment替换getTargetFragment

在这里,您还可以使用用户onRequestUpdate代替onActivityResult

这是一个定制的解决方案,不需要考虑您使用的片段管理器


使用getFragmentManager()而不是getChildFragmentManager()也可以,但会影响getParentFragment()。如果您不将getChildFragmentManager()用于嵌套片段,那么您将无法通过在子片段/嵌套片段中使用getParentFragment()来获取父片段。

在处理应用程序时,我遇到了相同的问题,我通过(在kotlin中)解决了它

也就是说

chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION); 

chooseRegionFragment.show(ParentFragment.this.getParentFragmentManager, TAG);

在java中,这是一个bug,因为我看到了其他报告,所以需要在问题跟踪器中填写bug报告。但是我不确定这个bug是在v4支持库中还是在Android本身中。所以你应该试着使用内置的片段,而不是v4,看看是否有什么变化。有人发现这是否是支持库吗?我认为这个问题是由Android O“修复”片段相关的bug引起的。我相信以前版本的android允许坏代码按预期工作。我可能错了。伙计们,我通过将Fragment替换为V4 SupportFragment进行了检查。。但在这一点上,这个问题也是存在的。。。Oreo一直在检查他们的旧bug…是的,这个解决方案在N_MR1之后正常工作,我们应该使用getFragmentManager,而从JELLY_BEAN_MR1到N_MR1,似乎应该使用getChildFragmentManager。嘿,但是如果我使用getFragmentManager()而不是getChildFragmentManager(),childFragment.getParent()将返回null。如何解决这个问题?使用getFragmentManager()而不是getChildFragmentManager()可以工作,但会影响getParentFragment()。如果不对嵌套片段使用getChildFragmentManager(),则无法通过在子/嵌套片段中使用getParentFragment()来获取父片段。感谢您指向此修补程序。它无法解释两件事:1。为什么这是个坏主意?2.子片段调用数据并将数据发送回父片段的正确或更好的方法是什么。有什么想法吗?@AAP在两个不同的碎片中有两个碎片
chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION); 

chooseRegionFragment.show(ParentFragment.this.getParentFragmentManager, TAG);