从另一个片段返回后,片段不会重新附加到其托管的ViewPager。
托管片段的一个活动,其布局包含ViewPager(在下面的示例中为PageListFragment
)。 ViewPager由FragmentStateViewPagerAdapter填充。托管内部托管的单个片段(下例中的PageFragment
)可以打开包含一组新页面的子页面列表。
只要没有按下后退按钮,一切正常。一旦用户关闭其中一个子页面列表,就会重新创建先前的列表,但不会显示先前显示的页面。浏览父页面列表中的其他页面仍然有效。
可以在github上找到示例应用程序:
public class MainActivity extends FragmentActivity {
private static final String CURRENT_FRAGMENT = MainActivity.class.getCanonicalName() + ".CURRENT_FRAGMENT";
public static final String ARG_PARENTS = "Parents";
public void goInto(String mHostingLevel, String mPosition) {
Fragment hostingFragment = newHostingFragment(mHostingLevel, mPosition);
addFragment(hostingFragment);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addBaseFragment();
}
private void addBaseFragment() {
Fragment hostingFragment = newHostingFragment("", "");
addFragment(hostingFragment);
}
private Fragment newHostingFragment(String mHostingLevel, String oldPosition) {
Fragment hostingFragment = new PageListFragment();
Bundle args = new Bundle();
args.putString(ARG_PARENTS, mHostingLevel + oldPosition +" > ");
hostingFragment.setArguments(args);
return hostingFragment;
}
private void addFragment(Fragment hostingFragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentSpace, hostingFragment, CURRENT_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
}
public class PageListFragment extends Fragment {
private String mParentString;
public PageListFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_hosting, container, false);
}
@Override
public void onResume() {
mParentString = getArguments().getString(MainActivity.ARG_PARENTS);
ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewPager);
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
super.onResume();
}
private static class SimpleFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private String mHostingLevel;
public SimpleFragmentStatePagerAdapter(FragmentManager fm, String hostingLevel) {
super(fm);
this.mHostingLevel = hostingLevel;
}
@Override
public android.support.v4.app.Fragment getItem(int position) {
PageFragment pageFragment = new PageFragment();
Bundle args = new Bundle();
args.putString(MainActivity.ARG_PARENTS, mHostingLevel);
args.putInt(PageFragment.ARG_POSITION, position);
pageFragment.setArguments(args);
return pageFragment;
}
@Override
public int getCount() {
return 5;
}
}
}
public class PageFragment extends Fragment {
public static final String ARG_POSITION = "Position";
private String mHostingLevel;
private int mPosition;
public PageFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_page, container, false);
setupTextView(contentView);
setupButton(contentView);
return contentView;
}
private void setupTextView(View contentView) {
mPosition = getArguments().getInt(ARG_POSITION);
mHostingLevel = getArguments().getString(MainActivity.ARG_PARENTS);
TextView text = (TextView) contentView.findViewById(R.id.textView);
text.setText("Parent Fragments " + mHostingLevel + " \n\nCurrent Fragment "+ mPosition);
}
private void setupButton(View contentView) {
Button button = (Button) contentView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openNewLevel();
}
});
}
protected void openNewLevel() {
MainActivity activity = (MainActivity) getActivity();
activity.goInto(mHostingLevel, Integer.toString(mPosition));
}
}
答案 0 :(得分:140)
经过长时间的调查,结果证明片段管理器存在问题。
当使用像上面那样的构造时,片段事务将片段重新附加到页面列表中会被静默丢弃。这基本上是导致
的问题java.lang.IllegalStateException: Recursive entry to executePendingTransactions
尝试更改FragmentPager中的片段时。
对于此错误的问题,同样的解决方案也适用于此处。构造FragmentStatePagerAdapter时,请提供正确的子片段管理器。
而不是
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
DO
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getChildFragmentManager(),mParentString));
另请参阅:github
答案 1 :(得分:10)
保罗没有提到的是,如果你使用 getChildFragmentManager ,那么你将在背面按下"空白屏幕"问题。
答案 2 :(得分:2)
在我的案例中,层次结构是:
MainActivity
-> MainFragment
-> TabLayout
+ ViewPager
-> AccountsFragment
+ SavingsFragment
+ InvestmentsFragment
等。< / p>
我遇到的问题是,我无法使用childFragmentManager
,原因是单击了Account view
项目(该项目位于{{ 1}})需要替换Fragment
,即整个屏幕。
使用ViewPager
的主机MainFragment
,即传递MainFragment
启用了替换,但是在弹出后退堆栈时,我得到了以下屏幕:
通过查看Fragment
为空的布局检查器,这也很明显。
显然,在查看还原的getFragmentManager()
时,您会注意到它们的ViewPager
已还原,但与弹出状态的层次结构不匹配。为了产生最小的影响并且不强制重新创建Fragment
,我通过以下更改重新编写了View
:
我复制了Fragment
的整个代码并进行了更改
FragmentStatePagerAdapter
使用
FragmentStatePagerAdapter
这样,我可以有效地确保已恢复的@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
...
}
被重新附加到@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.detach(f);
mCurTransaction.attach(f);
return f;
}
}
...
}
。
答案 3 :(得分:0)
当您返回到Viewpager屏幕时,由于FragmentStatePagerAdapter没有重新连接页面片段,因此页面片段未附加。解决方法是,在调用popbackstack()之后删除viewpager中的所有片段,这将使它们可以由您的初始代码重新添加。
[此示例用Kotlin语言编写]
//Clear all fragments from the adapter before they are re-added.
for (i: Int in 0 until adapter.count) {
val item = childFragmentManager.findFragmentByTag("f$i")
if (item != null) {
adapter.destroyItem(container!!, i, item)
}
}