Zusammenfassung des Problems
Hinweis: In dieser Antwort werde ich auf FragmentPagerAdapter
den Quellcode verweisen . Die allgemeine Lösung sollte aber auch für gelten FragmentStatePagerAdapter
.
Wenn Sie dies lesen Sie wahrscheinlich bereits wissen , dass FragmentPagerAdapter
/ FragmentStatePagerAdapter
sollte schaffen Fragments
für Ihre ViewPager
, sondern auf Aktivität Erholung (ob von einem Gerät Rotation oder dem System zu töten Ihre App wieder Speicher) diese Fragments
werden nicht wieder angelegt, sondern ihre Instanzen aus demFragmentManager
. Sagen Sie nun, dass Sie Activity
einen Verweis auf diese Fragments
benötigen, um daran arbeiten zu können. Sie haben kein id
oder tag
für diese erstellt, Fragments
weil Sie FragmentPagerAdapter
sie intern festlegen . Das Problem ist also, wie man ohne diese Informationen einen Verweis auf sie erhält ...
Problem mit aktuellen Lösungen: Verlassen Sie sich auf internen Code
Viele der Lösungen, die ich für diese und ähnliche Fragen gesehen habe, basieren darauf, einen Verweis auf das Vorhandene zu erhalten Fragment
, FragmentManager.findFragmentByTag()
indem das intern erstellte Tag"android:switcher:" + viewId + ":" + id
aufgerufen und nachgeahmt wird : . Das Problem dabei ist, dass Sie sich auf internen Quellcode verlassen, der bekanntlich nicht für immer gleich bleibt. Die Android-Ingenieure bei Google könnten leicht entscheiden, die tag
Struktur zu ändern, die Ihren Code beschädigen würde, sodass Sie keinen Verweis auf den vorhandenen finden können Fragments
.
Alternative Lösung ohne interne tag
Hier ist ein einfaches Beispiel dafür, wie Sie einen Verweis auf das Fragments
zurückgegebene erhalten FragmentPagerAdapter
, das nicht von der internen tags
Menge auf dem abhängt Fragments
. Der Schlüssel besteht darin instantiateItem()
, Referenzen dort zu überschreiben und zu speichern, anstatt in 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();
}
}
}
oder wenn Sie arbeiten lieber mit tags
statt Klasse Membervariablen / Verweis auf die Fragments
Sie kann auch den greifen tags
Satz von FragmentPagerAdapter
auf die gleiche Weise: HINWEIS: dies gilt nicht , FragmentStatePagerAdapter
da es nicht gesetzt ist , tags
wenn seine Erstellung Fragments
.
@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;
}
Beachten Sie, dass diese Methode NICHT auf der Nachahmung des internen tag
Satzes durch beruht FragmentPagerAdapter
und stattdessen geeignete APIs zum Abrufen verwendet. Auf diese Weise sind Sie auch dann sicher, wenn Sie tag
Änderungen in zukünftigen Versionen von vornehmen SupportLibrary
.
Vergessen Sie nicht, dass das Design Activity
, an dem Fragments
Sie arbeiten möchten , je nach Design möglicherweise noch vorhanden ist oder nicht. Sie müssen dies berücksichtigen, indem Sie null
Überprüfungen durchführen, bevor Sie Ihre Referenzen verwenden.
Wenn Sie stattdessen mit arbeiten FragmentStatePagerAdapter
, möchten Sie keine harten Verweise auf Ihre behalten, Fragments
da Sie möglicherweise viele davon haben und harte Verweise sie unnötigerweise im Speicher behalten würden. Speichern Sie stattdessen die Fragment
Referenzen in WeakReference
Variablen anstelle von Standardreferenzen. So was:
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...
}