Java 更改屏幕旋转时 ViewPager 片段消失
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18075853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ViewPager fragments disappear when change screen rotation
提问by Heysem Katibi
I'm working on android application that contains ViewPager
with Fragment
s, like this:
我的工作包含Android应用程序ViewPager
与Fragment
S,这样的:
MainActivity
(MainActivityFragment
(screenSlideViewPager
(Fragment
s))), which means:
MainActivity
( MainActivityFragment
( screenSlideViewPager
( Fragment
s))),这意味着:
Activity
containsFragment
containsViewPager
containsFragment
s
Activity
包含Fragment
包含ViewPager
包含Fragment
s
Now my problem is when rotate device or change screen rotation all Fragments in ViewPager are disappear.
现在我的问题是当旋转设备或更改屏幕旋转时,ViewPager 中的所有 Fragment 都会消失。
any ideas to solve this issue?
任何想法来解决这个问题?
EDIT 1
编辑 1
MainActivity.java:
主活动.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentByTag(TAG) == null) {
final FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.add(android.R.id.content, new MainActivityFragment(), TAG);
ft.commit();
}
}
MainActivityFragment.java:
MainActivityFragment.java:
public class MainActivityFragment extends Fragment {
private ViewPager mPager = null;
private PagerAdapter mPageAdapter = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View reVal = inflater.inflate(R.layout.activity_main, container, false);
mPager = (ViewPager) reVal.findViewById(R.id.pagerMainContent);
mPageAdapter = new ScreenSlidePagerAdapter(getActivity().getFragmentManager());
mPager.setAdapter(mPageAdapter);
return reVal;
}
private MainGridViewFragment mainGridFragment;
private AlphabetGridViewFragment alphabetGridFragment;
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public android.app.Fragment getItem(int position) {
switch (position) {
case 1:
mainGridFragment = new MainGridViewFragment();
return mainGridFragment;
case 0:
alphabetGridFragment = new AlphabetGridViewFragment();
return alphabetGridFragment;
default:
return null;
}
}
@Override
public int getCount() {
return 2;
}
}
}
EDIT 2
编辑 2
Obviously MainActivity
and MainActivityFragment
are loaded, and the proof is The ActionBar
,
notice also that ViewPager
is loaded too, because you still can navigate between pages (the blue light means that the pager reached to last page) but you can't see its content.
显然MainActivity
和MainActivityFragment
已加载,并且证明是 The ActionBar
,请注意也ViewPager
已加载,因为您仍然可以在页面之间导航(蓝灯表示寻呼机到达最后一页)但您看不到其内容。
采纳答案by Jon
It looks like your main activity is using the getSupportFragmentManager() while your fragment is using getFragmentManager().
看起来您的主要活动正在使用 getSupportFragmentManager() 而您的片段正在使用 getFragmentManager()。
Not sure if this is worthy of an answer post but my rating is too low to reply any other way. :)
不确定这是否值得发帖回复,但我的评分太低,无法以任何其他方式回复。:)
Edit: I believe you may also need to extend a FragmentActivity with the support library.
编辑:我相信您可能还需要使用支持库扩展 FragmentActivity。
See: https://stackoverflow.com/a/10609839/2640693
参见:https: //stackoverflow.com/a/10609839/2640693
Edit 2:
编辑2:
public class MainActivityFragment extends FragmentActivity {
private ViewPager mPager = null;
private PagerAdapter mPageAdapter = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View reVal = inflater.inflate(R.layout.activity_main, container, false);
mPager = (ViewPager) reVal.findViewById(R.id.pagerMainContent);
mPageAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
mPager.setAdapter(mPageAdapter);
return reVal;
}
private MainGridViewFragment mainGridFragment;
private AlphabetGridViewFragment alphabetGridFragment;
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 1:
mainGridFragment = new MainGridViewFragment();
return (Fragment)mainGridFragment;
case 0:
alphabetGridFragment = new AlphabetGridViewFragment();
return (Fragment)alphabetGridFragment;
default:
return null;
}
}
@Override
public int getCount() {
return 2;
}
}
}
回答by android developer
Avoid creating the viewpager again. Put the code of onCreateView in onCreate(). And make your fragment use onRetainInstance(true). Hence this shall not recreate the fragment and again because the view is in the onCreate(), it will not be called again.
避免再次创建 viewpager。将 onCreateView 的代码放在 onCreate() 中。并使您的片段使用 onRetainInstance(true)。因此,这不会重新创建片段,因为视图在 onCreate() 中,因此不会再次被调用。
Check in the onCreateView() whether the view exists, if so then remove it. Snippets:
检查 onCreateView() 视图是否存在,如果存在则将其删除。片段:
//creates the view
private View createView(Bundle savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(your_layout, null, false);
//viewpager
return view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//retains fragment instance across Activity re-creation
setRetainInstance(true);
viewRoot = createView(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (viewRoot != null && viewRoot.getParent() != null) {
ViewGroup parent = (ViewGroup) viewRoot.getParent();
parent.removeView(viewRoot);
Log.i("Test", "**************view.getParent(): " + viewRoot.getParent() + " " + viewRoot);
}
return viewRoot;
}
回答by Fatimehin Dare
You should rather use a getChildFragmentManager()
instead of the getFragmentManager()
.
You used
您应该使用 agetChildFragmentManager()
而不是getFragmentManager()
。你用过
mPageAdapter = new ScreenSlidePagerAdapter(getActivity().getFragmentManager());
it should have been
应该是
mPageAdapter = new ScreenSlidePagerAdapter(getActivity().getChildFragmentManager());
in your fragment
在你的片段中
回答by chubbsondubs
I had this exact same problem. It's tremendously confusing, but this thread helped me out except that the answers didn't really explain why it works.
我有这个完全相同的问题。这非常令人困惑,但是这个线程帮助了我,只是答案并没有真正解释它为什么起作用。
The fix to this problem is to use Fragment.getChildFragmentManager()
. What's so confusing is the android API has Activity.getFragmentManager()
, but if you are trying to support older devices you need to use Activity.getSupportFragmentManager()
. However, this particular problem isn't about supporting older APIs.
解决此问题的方法是使用Fragment.getChildFragmentManager()
. 什么是如此混乱是Android API有Activity.getFragmentManager()
,但如果你想支持老设备,你需要使用Activity.getSupportFragmentManager()
。但是,这个特殊问题与支持旧 API 无关。
The problem is that you have a Activity which has a Fragment which owns the ViewPager which owns several Fragments. You have Fragments within Fragments! The original design of Fragments didn't really handle this use case and later was updated to handle it. When you have Fragments within Fragments you need to use:
问题是你有一个 Activity,它有一个 Fragment,它拥有 ViewPager,它拥有多个 Fragment。你有片段中的片段!Fragments 的原始设计并没有真正处理这个用例,后来被更新来处理它。当您在 Fragments 中有 Fragments 时,您需要使用:
Fragment.getChildFragmentManager()
Fragment.getChildFragmentManager()
From within a Fragment
you have the choice of Fragment.getFragmentManager()
which returns the FragmentManager
of the Activity
vs Fragment.getChildFragmentManager()
which returns the FragmentManager
for this Fragment
which properly scopes the Fragment
s within your Fragment
.
从内Fragment
你的选择Fragment.getFragmentManager()
,它返回FragmentManager
的的Activity
VSFragment.getChildFragmentManager()
返回了FragmentManager
此Fragment
其正常范围限定Fragment
的范围内小号Fragment
。
回答by Tiago Oliveira
For the ones that are having problems with this you can try this:
对于有此问题的人,您可以尝试以下操作:
private void InitializeUI(){
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.activity_exame2);
InitializeUI();
}
i spent 2 days around this problem this was the only thing that worked for me, remeber to add android:configChanges="screenSize|orientation" to your activity in manifest
我花了 2 天时间解决这个问题,这是唯一对我有用的方法,记得在清单中将 android:configChanges="screenSize|orientation" 添加到您的活动中
回答by Kalpesh
I tried many solution but get success in any one. At last I fixed as below:
我尝试了很多解决方案,但在任何一个中都取得了成功。最后我固定如下:
Use getActivity().getSupportFragmentManager() rather than getChildFragmentManager()
Override getItemId(int position) method in your ViewPagerAdapter class like below:
@Override public long getItemId(int position) { return System.currentTimeMillis(); }
使用 getActivity().getSupportFragmentManager() 而不是 getChildFragmentManager()
在 ViewPagerAdapter 类中覆盖 getItemId(int position) 方法,如下所示:
@Override public long getItemId(int position) { return System.currentTimeMillis(); }
For me it's working like charm, please also comment here your view.
对我来说,它就像魅力一样工作,也请在这里评论您的观点。
回答by 10101101
In my case there is activity A which has fragment F1, which has viewpager V1, which has fragment F2, which has viewpager V2, which has fragment F3. :)
在我的例子中,活动 A 有片段 F1,它有 viewpager V1,它有片段 F2,它有 viewpager V2,它有片段 F3。:)
This last fragment F3, when rotated, either gives blank or error.
最后一个片段 F3,当旋转时,要么给出空白,要么出错。
My solution was to:
我的解决方案是:
- Remove PageChangeListener, so basicly not use fragment transactions when changing fragments, instead leave as it is default.
- Use FragmentStatePagerAdapter instead of FragmentPagerAdapter
- Override getItemPosition() in adapter and return POSITION_NONE
- Create a field with List of Fragments in adapter and set it in constructor
- In getItem() in adapter just return fragmentList.get(position)
- In getCount() in adapter just return fragmentList.size()
- NOT OVERRIDE any other methods in adapter like destroy, instantiate etc
- Create and instantiate V2 adapter in onCreateView() of F2
- 移除 PageChangeListener,所以在更改片段时基本上不使用片段事务,而是保留默认值。
- 使用 FragmentStatePagerAdapter 而不是 FragmentPagerAdapter
- 覆盖适配器中的 getItemPosition() 并返回 POSITION_NONE
- 在适配器中创建一个带有片段列表的字段并将其设置在构造函数中
- 在适配器中的 getItem() 中只返回 fragmentList.get(position)
- 在适配器中的 getCount() 中只返回 fragmentList.size()
- 不要覆盖适配器中的任何其他方法,如销毁、实例化等
- 在 F2 的 onCreateView() 中创建和实例化 V2 适配器
EDIT
编辑
When for example need to replace V1 in F1 with V2 in F2 then:
例如,当需要用 F2 中的 V2 替换 F1 中的 V1 时:
- Enclose V1 inside say relative layout with F1_container id
- Use getSupportFragmentManager() and begin transaction
- Remove F1
- Replace F1_container with F2
- Add to backstack
- Commit transaction
- 用 F1_container id 将 V1 放在里面说相对布局
- 使用 getSupportFragmentManager() 并开始事务
- 删除 F1
- 用 F2 替换 F1_container
- 添加到后台
- 提交交易
Later when need to comeback from F2 to F1 call popBackStack() on valid A reference.
稍后当需要从 F2 返回到 F1 时,在有效的 A 引用上调用 popBackStack()。
And think thats it, took more than a day of changing each of those and restarting app and see result. Hope this helps.
想想就是这样,花了一天多的时间来改变每一个并重新启动应用程序并查看结果。希望这可以帮助。