[英]Android ViewPager with tab not maintaining state after screen rotation
I'm implementing a ViewPager with tabs similar to implementation provided by Google here . 我执行与标签类似,由谷歌提供的实施ViewPager 这里 。
My app has the following behaviour. 我的应用有以下行为。 My ViewPager has 3 "pages" (fragA, fragB, fragC) and I'm implementing 3 tabs on top of the ViewPager. 我的ViewPager有3个“页面”(fragA,fragB,fragC),我在ViewPager上面实现了3个标签。 The differece between google's implementation and mine is that the tabs aren't used to navigate between fragments. 谷歌的实现和我的实现之间的区别在于标签不用于在片段之间导航。 As an example, pressing one of my tabs, loads a different set of data on the visible fragment. 例如,按下我的一个选项卡,在可见片段上加载一组不同的数据。 I can have fragA with tab3 selected, fragB with tab2 selected and fragC with tab1 selected. 我可以选择tab3选择fragA,选择tab2选择fragB,选择tab1选择fragC。
The problem is when I rotate the screen. 问题是当我旋转屏幕时。 If I'm on FragmentA
with the third tab selected, when I rotate the screen, I stay in the same fragment but now, the first tab is selected. 如果我在FragmentA
上选择了第三个选项卡,当我旋转屏幕时,我会保持相同的片段,但现在,第一个选项卡被选中。 I want to maintain the same tab selected when rotating the screen. 我希望在旋转屏幕时保持选择相同的选项卡。
This is my class for managing the tabs: 这是我管理标签的类:
public class ManagerTabs extends Fragment {
private TabHost.TabContentFactory mFactory = new TabHost.TabContentFactory() {
@Override
public View createTabContent(String tag) {
View v = new View(getActivity());
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
};
public static ManagerTabs newManager() {
return new ManagerTabs();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.datatabs, container, false);
createTabs();
createPager();
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null) {
currentPage = savedInstanceState.getInt("currentPage", currentPage);
currentTab = savedInstanceState.getInt("currentTab", currentTab);
mTabHost.setCurrentTab(currentTab);
}
mPager.setCurrentItem(currentPage);
}
private void createPager() {
mPager = (ViewPager) view.findViewById(R.id.datapager);
pagerAdapter = new PagerAdapter(getChildFragmentManager());
mPager.setAdapter(pagerAdapter);
IconPageIndicator indicator = (IconPageIndicator) rootView.findViewById(R.id.indicator);
indicator.setViewPager(pager);
indicator.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
currentTab = mTabHost.getCurrentTab();
currentPage = mPager.getCurrentItem();
switch (currentPage) {
case 0:
((FragmentA) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
break;
case 1:
((FragmentB) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
break;
case 2:
((FragmentC) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
break;
}
}
});
}
private void createTabs() {
mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
mTabHost.setup();
mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.day))setIndicator(getString(R.string.day)).setContent(mFactory));
mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.month)).setIndicator(getString(R.string.month)).setContent(mFactory));
mTabHost.addTab(mTabHost.newTabSpec(getString(R.string.year)).setIndicator(getString(R.string.year)).setContent(mFactory));
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
public void onTabChanged(String tag) {
currentTab = mTabHost.getCurrentTab();
currentPage = mPager.getCurrentItem();
switch (currentPage) {
case 0:
((FragmentA) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
break;
case 1:
((FragmentB) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
break;
case 2:
((FragmentC) pagerAdapter.getCurrentFragment(currentPage)).getData(currentTab);
break;
}
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("currentPage", mPager.getCurrentItem());
outState.putInt("currentTab", mTabHost.getCurrentTab());
}
}
And this is the adapter that creates the fragments: 这是创建片段的适配器:
public class PagerAdapter extends FragmentPagerAdapter implements IconPagerAdapter{
private Fragment[] currentFragment = new Fragment[3];
public PagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int index) {
Fragment fragment;
switch (index) {
case 0:
fragment = FragmentA.newInstance();
break;
case 1:
fragment = FragmentB.newInstance();
break;
case 2:
fragment = FragmentC.newInstance();
break;
default:
fragment = null;
break;
}
currentFragment[index] = fragment;
return fragment;
}
@Override
public int getIconResId(int index) {
switch (index) {
case 0:
return R.drawable.fraga;
case 1:
return R.drawable.fragb;
case 2:
return R.drawable.fragc;
default:
return -1;
}
}
@Override
public int getCount() {
return 3;
}
public Fragment getCurrentFragment(int currentFrag) {
return currentFragment[currentFrag];
}
public Fragment[] getCurrentFragment() {
return currentFragment;
}
}
And finally, a Fragment (FragmentA, FragmentB and FragmentC) are almost identically: 最后,片段(FragmentA,FragmentB和FragmentC)几乎完全相同:
public class FragmentA extends Fragment {
public static FragmentA newInstance() {
return new FragmentA();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.datafragment, container, false);
mTabHost = (TabHost) ((View) container.getParent().getParent()).findViewById(android.R.id.tabhost);
if (savedInstanceState != null) {
currentTab = savedInstanceState.getInt("currentTab");
}
populateLayout(currentTab);
return rootView;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("currentTab", currentTab);
}
}
The problem is that all my onCreateView
are always called twice and the second time that they are called, the information is lost. 问题是我的所有onCreateView
总是被调用两次,第二次调用它们时,信息就会丢失。 I've debugged and saw this behavior, 我已经调试并看到了这种行为,
When I rotate the screen, for example in FragmentA and with the third tab selected, this happens: 当我旋转屏幕时,例如在FragmentA中并选择第三个选项卡时,会发生以下情况:
01 ManagerTabs -> onSaveInstanceState
02 FragmentA -> onSaveInstanceState
03 ManagerTabs -> onCreateView
04 ManagerTabs -> onViewCreated
In the 04 call (ManagerTabs -> onViewCreated), mTabHost.setCurrentTab(currentTab);
在04调用(ManagerTabs - > onViewCreated), mTabHost.setCurrentTab(currentTab);
is called but inside onTabChanged
, I get an java.lang.NullPointerException
because all the fragments inside the adapter are all null. 在onTabChanged
被调用,我得到一个java.lang.NullPointerException
因为适配器内的所有片段都是null。
What can I do so that if I rotate the screen, I can maintain the current selected tab? 我该怎么办,如果我旋转屏幕,我可以保持当前选定的标签?
After screen rotation new instance of FragmentPagerAdapter
is created. 屏幕旋转后,将创建FragmentPagerAdapter
新实例。 But the ViewPager
restores its state and state of all fragments it contains. 但ViewPager
恢复其包含的所有片段的状态和状态。 ViewPager
doesn't call adapters getView()
method. ViewPager
不调用适配器getView()
方法。 Therefore Fragment[] currentFragment
contains null
values only. 因此, Fragment[] currentFragment
仅包含null
值。
You can get current fragment by another ways. 您可以通过其他方式获取当前片段。
If using FragmentPagerAdapter
: 如果使用FragmentPagerAdapter
:
FragmentPagerAdapter
sets tags on fragments it passes to FragmentManager
. FragmentPagerAdapter
在它传递给FragmentManager
FragmentPagerAdapter
设置标签。 This id depends on page index. 此id取决于页面索引。 How this id is generated you can see in source of the latest support lib . 如何生成此id,您可以在最新的支持库的源代码中看到。
To achieve this just add following method to your ManagerTabs
fragment: 要实现此目的,只需在ManagerTabs
片段中添加以下方法:
public Fragment getCurrentPagerFragment(int position) {
String fragmentTag = "android:switcher:" + mPager.getId() + ":" + position;
return getChildFragmentManager().findFragmentByTag(fragmentTag);
}
If using FragmentStatePagerAdapter
: 如果使用FragmentStatePagerAdapter
:
It doesn't sets tags on fragments. 它不会在片段上设置标签。 With FragmentStatePagerAdapter
it seems we can get by, using its instantiateItem(ViewGroup container, int position)
call. 使用FragmentStatePagerAdapter
,我们可以使用其instantiateItem(ViewGroup container, int position)
调用来获取。 It returns reference to fragment at position position
. 它返回对位置position
片段的引用。 If FragmentStatePagerAdapter
already holds reference to fragment in question, instantiateItem
just returns reference to that fragment, and doesn't call getItem()
to instantiate it again. 如果FragmentStatePagerAdapter
已经持有对相关片段的引用,则instantiateItem
只返回对该片段的引用,并且不会调用getItem()
再次实例化它。 In this case our method will be: 在这种情况下,我们的方法将是:
public Fragment getCurrentPagerFragment(int position) {
FragmentStatePagerAdapter a = (FragmentStatePagerAdapter) mPager.getAdapter();
return (Fragment) a.instantiateItem(pager, position);
}
Finally: 最后:
Now use above method to get current fragment. 现在使用上面的方法来获取当前片段。 In your case: 在你的情况下:
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
public void onTabChanged(String tag) {
currentTab = mTabHost.getCurrentTab();
currentPage = mPager.getCurrentItem();
Fragment currentFragment = getCurrentPagerFragment(currentPage);
switch (currentPage) {
case 0:
((FragmentA) currentFragment).getData(currentTab);
break;
case 1:
((FragmentB) currentFragment).getData(currentTab);
break;
case 2:
((FragmentC) currentFragment).getData(currentTab);
break;
}
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.