Viewpager初始片段中的操作项未显示

sol*_*rnz 30 android android-fragments android-viewpager android-actionbar

在我正在开发的应用程序中,我正在使用带有片段的ViewPager,每个片段独立于ViewPager中的所有其他片段构建自己的菜单.

问题在于,有时默认情况下由ViewPager初始化的片段(即处于初始状态)没有将其项目填充到操作项菜单中.更糟糕的是,这个问题只是间歇性地发生.如果我在ViewPager中滑动足以让片段被迫重新初始化它们,当我向后滑动时,菜单会正确填充.

活动代码:

package net.solarnz.apps.fragmentsample;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;

public class FragmentSampleActivity extends Activity {
    private ViewPagerAdapter mViewPagerAdapter;
    private ViewPager mViewPager;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        if (mViewPagerAdapter == null) {
            mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager());
        }

        mViewPager = (ViewPager) findViewById(R.id.log_pager);
        mViewPager.setAdapter(mViewPagerAdapter);
        mViewPager.setCurrentItem(0);
    }


    private class ViewPagerAdapter extends FragmentStatePagerAdapter {
        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return 8;
        }

        @Override
        public Fragment getItem(int position) {
            Fragment f = Fragment1.newInstance(position);
            // f.setRetainInstance(true);
            f.setHasOptionsMenu(true);
            return f;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

片段代码:

package net.solarnz.apps.fragmentsample;

import android.app.Fragment;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;

public class Fragment1 extends Fragment {
    int mNum;

    static Fragment newInstance(int num) {
        Fragment1 f = new Fragment1();

        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putInt("num", num);
        f.setArguments(args);

        return f;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        mNum = getArguments() != null ? getArguments().getInt("num") : 0;
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_list, menu);
    }

}
Run Code Online (Sandbox Code Playgroud)

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

            <android.support.v4.view.ViewPager
                android:id="@+id/log_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

菜单:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_refresh"
          android:title="Refresh"
          android:icon="@android:drawable/ic_delete"
          android:showAsAction="ifRoom|withText" />
</menu>
Run Code Online (Sandbox Code Playgroud)

正在填充的操作菜单:http: //i.stack.imgur.com/QFMDd.png

未填充操作菜单:http: //i.stack.imgur.com/sH5Pp.png

Way*_*yne 22

你应该读这个(通过xcolw ...)

通过实验,似乎根本原因是invalidateOptionsMenu在主线程上不间断地被调用多个来处理排队的作业.一个猜测 - 如果菜单创建的某些关键部分是通过帖子延迟,将操作栏保持在错误状态直到它运行,这就很重要了.

这可能会发生一些不明显的点:

  1. 为同一项调用viewPager.setCurrentItem多次

  2. 在活动的onCreate中调用viewPager.setCurrentItem.setCurrentItem导致选项菜单无效,紧接着活动的选项菜单invalidate

我找到的解决方法

  1. 保护对viewPager.setCurrentItem的调用

    if (viewPager.getCurrentItem() != position)
        viewPager.setCurrentItem(position);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将调用推迟到onCreate中的viewPager.setCurrentItem

    public void onCreate(...) {
        ...
        view.post(new Runnable() {
            public void run() {
                // guarded viewPager.setCurrentItem
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

在这些更改后,视图寻呼机内的选项菜单似乎按预期工作.我希望有人能够更多地了解这一点.

来源 http://code.google.com/p/android/issues/detail?id=29472


sol*_*rnz 8

简单的答案是不要在ViewPager中使用片段内的菜单.如果你确实需要在片段中使用菜单,我建议通过父Activity中的onCreateOptionsMenu方法加载菜单.显然,您需要能够确定要显示的菜单.

我能够通过使用类反射来实现这一点.每次切换页面时,还需要使用invalidateOptionsMenu方法.当ViewPager更改页面时,您将需要一个OnPageChangeListener来调用它.