我有一个浏览片段的viewpager。我的FragmentPagerAdapter
子类在getItem
方法中创建了一个看似浪费的新片段。是否FragmentPagerAdapter
与convertView
中的listAdapter
等效,可以重复使用已创建的片段?我的代码如下。
public class ProfilePagerAdapter extends FragmentPagerAdapter {
ArrayList<Profile> mProfiles = new ArrayList<Profile>();
public ProfilePagerAdapter(FragmentManager fm) {
super(fm);
}
/**
* Adding a new profile object created a new page in the pager this adapter is set to.
* @param profile
*/
public void addProfile(Profile profile){
mProfiles.add(profile);
}
@Override
public int getCount() {
return mProfiles.size();
}
@Override
public Fragment getItem(int position) {
return new ProfileFragment(mProfiles.get(position));
}
}
答案 0 :(得分:100)
FragmentPagerAdapter
已为您缓存Fragments
。每个片段都分配了一个标记,然后FragmentPagerAdapter
尝试调用findFragmentByTag
。如果getItem
的结果为findFragmentByTag
,则只会调用null
。所以你不应该自己缓存片段。
答案 1 :(得分:67)
杰夫的帖子附录:
您可以使用findFragmentByTag()
引用Fragment
中的FragmentPagerAdapter
。标签的名称以这种方式生成:
private static String makeFragmentName(int viewId, int index)
{
return "android:switcher:" + viewId + ":" + index;
}
其中viewId是ViewPager的id
答案 2 :(得分:23)
似乎很多人在查看此问题时都在寻找一种方法来引用由Fragments
/ FragmentPagerAdapter
创建的FragmentStatePagerAdapter
。我想提供我的解决方案,而不依赖于内部创建的tags
,其他答案就在这里使用。
作为奖励,此方法也适用于FragmentStatePagerAdapter
。有关详细信息,请参阅下面的注释。
我在此问题和类似问题上看到的很多解决方案都依赖于通过调用Fragment
和模仿internally created tag: "android:switcher:" + viewId + ":" + id
来获取对现有FragmentManager.findFragmentByTag()
的引用。这样做的问题在于你依赖于内部源代码,我们都知道并不能保证它们永远保持不变。 Google的Android工程师可以轻松决定更改tag
结构,这会破坏您的代码,导致您无法找到对现有Fragments
的引用。
tag
以下是一个简单的示例,说明如何获取Fragments
返回的FragmentPagerAdapter
的引用,该引用不依赖于tags
上的内部Fragments
集。关键是覆盖instantiateItem()
并保存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
的类成员变量/引用,您还可以获取tags
设置的FragmentPagerAdapter
1}}以同样的方式:
注意:这不适用于FragmentStatePagerAdapter
,因为它在创建tags
时未设置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;
}
请注意,此方法不依赖于模仿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...
}
答案 3 :(得分:17)
如果片段仍在内存中,您可以使用此功能找到它。
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
return getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + getViewPager().getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
v4支持api的示例代码。
答案 4 :(得分:0)
供将来的读者使用!
如果您想通过viewpager重用片段,最好的解决方案是使用ViewPager 2,因为 View Pager 2使用了RecyclerView。