問題の概要
注: この回答ではFragmentPagerAdapter、そのソース コードを参照します。しかし、一般的な解決策は にも適用されFragmentStatePagerAdapterます。
これを読んでいる場合は、FragmentPagerAdapter/が のために作成するFragmentStatePagerAdapterことを意図していることをおそらく既に知っているでしょうが、アクティビティの再作成時に (デバイスのローテーションまたはシステムがアプリを強制終了してメモリを回復するため)、これらは再度作成されることはありませんが、代わりにそのから取得したインスタンス。ここで、作業を行うためにこれらへの参照を取得する必要があるとします。内部で設定されているため、作成されたこれらのまたははありません。問題は、その情報なしでそれらへの参照を取得する方法です...FragmentsViewPagerFragmentsFragmentManagerActivityFragmentsidtagFragmentsFragmentPagerAdapter
現在のソリューションの問題: 内部コードに依存している
this および同様の質問で私が見た多くの解決策は、内部で作成されたタグFragmentを呼び出しFragmentManager.findFragmentByTag()て模倣することにより、既存のものへの参照を取得することに依存しています: 。これに関する問題は、内部ソース コードに依存していることです。これは、誰もが知っているように、永久に同じままであるとは限りません。Google の Android エンジニアは、既存の."android:switcher:" + viewId + ":" + idtagFragments
内部に依存しない代替ソリューションtag
の内部セットに依存しないFragmentsによって返されるへの参照を取得する方法の簡単な例を次に示します。重要なのは、 inではなくそこに参照をオーバーライドして保存することです。FragmentPagerAdaptertagsFragmentsinstantiateItem()getItem()
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
またはtags、クラス メンバー変数/への参照の代わりに作業したい場合は、同じ方法でセットをFragments取得することもできます。tagsFragmentPagerAdapterFragmentStatePagerAdaptertagsFragments
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
このメソッドは、内部tagセットの模倣に依存せずFragmentPagerAdapter、代わりにそれらを取得するために適切な API を使用することに注意してください。これtagにより、 の将来のバージョンで変更が加えられた場合SupportLibraryでも、安全を保つことができます。
の設計に応じて、Activity作業Fragmentsしようとしている がまだ存在する場合と存在しない場合があることを忘れないnullでください。そのため、参照を使用する前にチェックを行ってそのことを考慮する必要があります。
また、代わりにを使用している場合はFragmentStatePagerAdapter、 へのハード参照を保持したくありませんFragments。それらのハード参照が多数ある可能性があり、ハード参照はそれらを不必要にメモリに保持するからです。Fragment代わりに、参照を標準の変数ではなく変数に保存しWeakReferenceます。このような:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}