我正在使用ViewPager中的一些片段构建一个Android应用程序(最低SDK级别10,Gingerbread 2.3.3)。我正在使用ActionBarSherlock创建一个ActionBar和android-viewpagertabs来向ViewPager添加标签,就像在Market客户端中一样。
我想要在每个标签/片段上显示一个全局菜单项。在三个选项卡中的第一个,我想要两个额外的菜单项。
但现在发生了两件奇怪的事情:
首先,如果我启动应用程序,一切似乎都很好,我可以看到第一页上的所有三个菜单项,如果我滑动到第二个和第三个选项卡,只能看到一个项目。但是,如果我从第三个选项卡滑回到第二个选项卡,我可以再次看到所有这三个项目,这不应该发生。如果我再次滑回第一个选项卡,然后再转到第二个选项卡,一切都很好。
另一个奇怪的事情是,每次旋转设备时,片段中的菜单项都会再次添加,即使它们已经在菜单中。
显示ViewPager及其选项卡的FragmentActivity代码:
public class MainActivity extends FragmentActivity {
public static final String TAG = "MainActivity";
private ActionBar actionBar;
private Adapter adapter;
private ViewPager viewPager;
private ViewPagerTabs tabs;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.volksempfaenger);
actionBar = getSupportActionBar();
adapter = new Adapter(getSupportFragmentManager());
adapter.addFragment(getString(R.string.title_tab_subscriptions),
SubscriptionGridFragment.class);
// adding more fragments here
viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(adapter);
tabs = (ViewPagerTabs) findViewById(R.id.tabs);
tabs.setViewPager(viewPager);
}
public static class Adapter extends FragmentPagerAdapter implements
ViewPagerTabProvider {
private FragmentManager fragmentManager;
private ArrayList<Class<? extends Fragment>> fragments;
private ArrayList<String> titles;
public Adapter(FragmentManager fm) {
super(fm);
fragmentManager = fm;
fragments = new ArrayList<Class<? extends Fragment>>();
titles = new ArrayList<String>();
}
public void addFragment(String title, Class<? extends Fragment> fragment) {
titles.add(title);
fragments.add(fragment);
}
@Override
public int getCount() {
return fragments.size();
}
public String getTitle(int position) {
return titles.get(position);
}
@Override
public Fragment getItem(int position) {
try {
return fragments.get(position).newInstance();
} catch (InstantiationException e) {
Log.wtf(TAG, e);
} catch (IllegalAccessException e) {
Log.wtf(TAG, e);
}
return null;
}
@Override
public Object instantiateItem(View container, int position) {
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
Fragment f = getItem(position);
fragmentTransaction.add(container.getId(), f);
fragmentTransaction.commit();
return f;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
BaseActivity.addGlobalMenu(this, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return BaseActivity.handleGlobalMenu(this, item);
}
}
应具有自己的菜单项的片段代码:
public class SubscriptionGridFragment extends Fragment {
private GridView subscriptionList;
private SubscriptionListAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
// ...
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.subscription_list, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// ...
}
}
答案 0 :(得分:1)
在Android示例项目中找到了这个。在片段活动中,onCreate需要检查savedInstanceState是否仍然有效,如下所示:
setContentView(R.layout.custom_detail_fragment);
if (savedInstanceState != null) {
return;
}
CDFrag = new CustomDetailFragment();
getSupportFragmentManager().beginTransaction().add(R.id.custom_detail_fragment_container, CDFrag).commit();
关键是这一部分:
if (savedInstanceState != null) {
return;
}
我还在操作栏中获取了重复的项目,当我旋转时,一旦我添加了该检查,复制就停止了。
答案 1 :(得分:1)
有同样的问题。
我的错误是我在oncreate中创建了一个新的Viewpager并设置为id
viewpager.setId(viewpager.hashcode());
setContentView(viewpager);
但这是一个很大的错误,因为在更改方向后,FragmentPagerAdapter会尝试重用旧的Fragments。它在FragmentManager中查找具有从viewpagers id和片段位置生成的id的片段。
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
容器是Viewpager。
<强>解决方案:强>
viewpager.setId(R.id.viewpager);
setContentView(viewpager);
答案 2 :(得分:0)
感谢来自freenode /#android-dev的SimonVT:“protip:在覆盖instantiateItem之前看看fragmentpageradapter实际上做了什么”
删除此方法解决了整个问题。