30

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

在 Android O 模拟器上运行我所有的 dialogFragments 现在都失败了:-

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)

我没有进行任何代码更改。

Android 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'

    }
4

8 回答 8

54

对我来说,这不仅是 Android O 上的问题,也是旧版本上的问题。我测试的最旧版本是 API Level 16。

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

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

ParentFragment.this自定义类在哪里扩展android.support.v4.app.FragmentMyFragment也扩展了此类,并且是片段的子ParentFragment片段(因此得名)。

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

不过,这似乎不是正确的方法。我将这些调用更改为:

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

所以片段自己决定使用哪个 FragmentManager 并且错误现在消失了。

希望这可以帮助某人。

于 2017-08-06T17:57:03.423 回答
17

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

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    getActivity().getFragmentManager().beginTransaction().add(dialogFrag, "dialog").commit();
else
    getChildFragmentManager().beginTransaction().add(dialogFrag,"dialog").commit();
于 2017-06-25T09:01:57.033 回答
6

当我们迁移到 Android Studio 3 并将支持库升级到版本 26 时,我刚刚在我目前正在处理的项目中遇到了同样的问题。突然之间,在不更改代码的情况下,我们得到了大量的这个异常。最后我发现了以下内容:

Google 在今年 1 月在 v4 Fragment Manager 的源代码中添加了一个新的“健全性检查”(不确定发布到哪个版本),如果它具有目标片段集和目标,则拒绝使用片段管理器添加片段在同一个 Fragment Manager 的活动 Fragment 中找不到 Fragment。补丁在这里有详细描述

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

于 2017-11-03T20:03:47.750 回答
6

我和 Markus Ressel 有同样的情况,但我使用的是 getChildFragmentManager()。我用 getFragmentManager() 替换了它,它解决了这个问题。

更新:我现在一直在使用 childFragmentManager 并有一些反馈。

在处理由片段(片段中的片段)托管的内部片段时,请使用 childFragmentManager。这个片段管理器与活动 getSupportFragmentManager 不同。两者不一样。这是关注点分离。

所以我制定了一个规则,托管子片段的片段将始终使用 childFragmentManager,不在主机片段内的东西可以使用 getSupportfragmentManager。

于 2017-08-28T04:12:36.327 回答
2

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

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

代替:

myDialogFragment.show(getFragmentManager(), TAG);
// or  
myDialogFragment.show(getSupportFragmentManager(), TAG);
// or  
myDialogFragment.show(getChildFragmentManager(), TAG);
于 2019-01-24T10:14:35.737 回答
2

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

chooseRegionFragment.setTargetFragment(this@ParentFragment, REQUEST_CODE_CHOOSE_REGION)

chooseRegionFragment.show(this@ParentFragment.parentFragmentManager, TAG)

它转化为

chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION); 

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

在java中

于 2020-04-24T19:25:16.033 回答
1

我的应用程序运行良好,直到将目标版本升级到 27 然后我在调用setTargetFragment(片段片段,int requestCode)时遇到同样的问题

例子:

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); 
  } 
于 2018-05-24T01:29:35.070 回答
1

使用以下解决方案,您无需担心您正在处理哪些片段管理器,

假设您必须使用 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;
}

}

然后,将 setTargetFragment 替换为 setRequestFragment,将 getTargetFragment 替换为 getRequestFragment。

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

这是一个自定义解决方案,无需担心您使用的是哪个片段管理器。

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

于 2019-03-01T06:03:44.763 回答