2

ViewPager にいくつかの Fragments を含む Android アプリケーション (最小 SDK レベル 10、Gingerbread 2.3.3) を構築しています。私は ActionBarSherlock を使用してActionBarを作成し、Android-viewpagertabsを使用してマーケット クライアントと同じように ViewPager にタブを追加しています。

すべてのタブ/フラグメントに表示したいグローバル メニュー項目が 1 つあります。3 つのタブのうちの最初のタブには、2 つの追加メニュー項目が必要です。

しかし、今、2 つの奇妙なことが起こります。

最初にアプリを起動すると、すべて問題ないように見えます。最初のページに 3 つのメニュー項目がすべて表示され、2 番目と 3 番目のタブにスワイプすると 1 つの項目しか表示されません。しかし、3 番目のタブから 2 番目のタブにスワイプすると、3 つのアイテムすべてが再び表示されますが、これは起こるべきではありません。最初のタブにスワイプしてから 2 番目のタブにスワイプすると、すべて問題なく動作します。

もう 1 つの奇妙な点は、デバイスを回転させるたびに、フラグメントのメニュー項目が既にメニューにあるにもかかわらず、再度追加されることです。

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

同じ問題がありました。

私の間違いは、oncreate で新しい Viewpager を作成し、id として設定したことです

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

しかし、これは大きな間違いでした。なぜなら、方向の変更後に FragmentPagerAdapter が古い Fragments を再利用しようとするからです。ビューページの ID とフラグメントの位置から生成された ID を持つ Fragment を FragmentManager で探します。

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 に答える
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 に答える
0

freenode/#android-dev の SimonVT に感謝します。

このメソッドを削除すると、問題全体が解決しました。

于 2011-11-20T18:34:07.190 に答える