2

我正在用 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) {
        // ...
    }
}
4

3 回答 3

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;
    }

当我旋转并添加该检查时,我还在操作栏中获得了重复的项目,重复停止了。

于 2012-08-24T19:59:48.397 回答
1

有同样的问题。

我的错误是我在 oncreate 中创建了一个新的 Viewpager 并设置为 id

viewpager.setId(viewpager.hashcode());
setContentView(viewpager);

但这是一个很大的错误,因为在方向更改后,FragmentPagerAdapter 会尝试重用旧的 Fragments。它在 FragmentManager 中查找具有从 viewpagers id 和 Fragment 位置生成的 id 的 Fragment。

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);
于 2013-02-23T18:37:10.650 回答
0

感谢来自 freenode/#android-dev 的 SimonVT:“protip:在覆盖 instantiateItem 之前看看 fragmentpageradapter 实际做了什么”

删除此方法解决了整个问题。

于 2011-11-20T18:34:07.190 回答