アプリケーションをAndroid O in Android Studio 3に移行しました
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で何が変更されましたか?
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'
}
私は同じ問題、間違いなくAndroidバグ。ターゲットとしてそれを使用して別のフラグメントからフラグメントを表示しているときに起こります。回避策として使用できます:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
getActivity().getFragmentManager().beginTransaction().add(dialogFrag, "dialog").commit();
else
getChildFragmentManager().beginTransaction().add(dialogFrag,"dialog").commit();
私にとって、これはAndroid 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 Resselと同じケースがありましたが、getChildFragmentManager()を使用していました。これをgetFragmentManager()に置き換えて、問題を解決しました。
更新:私は今childFragmentManagerで作業しており、いくつかのフィードバックがあります。
フラグメントによってホストされる内部フラグメント(つまり、フラグメント内のフラグメント)を扱う場合は、childFragmentManagerを使用します。このフラグメントマネージャーは、アクティビティgetSupportFragmentManagerとは異なります。 2つは同じではありません。それは懸念の分離です。
そのため、子フラグメントをホストするフラグメントは常にchildFragmentManagerを使用し、ホストフラグメント内にないものはgetSupportfragmentManagerを使用できるというルールを作成しました。
Android Studio 3に移行し、サポートライブラリをバージョン26にアップグレードしたときに、現在取り組んでいるプロジェクトで同じ問題に直面しました。コードを変更せずに突然、この例外が大量に発生し、最終的に次のことがわかりました。
Googleは、今年1月にv4 Fragment Managerのソースに新しい「健全性チェック」を追加しました(どのリリースが行われたかはわかりません)。これは、ターゲットフラグメントセットとターゲットがある場合、同じFragment Managerのアクティブなフラグメントにフラグメントが見つかりません。パッチについて詳しく説明します here
Ealierバージョンはそれを気にしていないようです。 Support Fragment Managerを使用して追加されたフラグメントが、親フラグメントをターゲットとしてサブフラグメントにChild Fragment Managerを使用したコード内のすべての領域を更新するのに数日かかりました。まあ、悪いコードを書くことに対するペナルティが遅れます。
ターゲットバージョンを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);
}
_
以下のソリューションを使用すれば、どのフラグメントマネージャーを扱っているか心配する必要はありません。
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に置き換えます。
ここでは、onActivityResultの代わりにonRequestUpdateを使用することもできます。
これは、使用しているフラグメントマネージャーを気にせずにカスタムソリューションです。
GetChildFragmentManager()の代わりにgetFragmentManager()を使用しても機能しますが、getParentFragment()に影響します。ネストされたフラグメントにgetChildFragmentManager()を使用しない場合、子/ネストされたフラグメントでgetParentFragment()を使用して親フラグメントを取得することはできません。
最近、アプリでAndroid Oを対象にしたときに同じ問題が発生しました。解決策として、次を使用します。
myDialogFragment.show(SettingsFragment.this.getFragmentManager(), TAG);
の代わりに:
myDialogFragment.show(getFragmentManager(), TAG);
// or
myDialogFragment.show(getSupportFragmentManager(), TAG);
// or
myDialogFragment.show(getChildFragmentManager(), TAG);