可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
In the application I am developing I am using a ViewPager with fragments and each fragment constructs its own menu independently of all of the other fragments in the ViewPager.
The issue is that sometimes the fragments that are initialised by the ViewPager by default (i.e in it's initial state) are not having their items populated into the action items menu. What's worse is that this issue only occurs intermittently. If I swipe through the ViewPager enough so that the fragments are forced to re-initialise them selves, when I swipe back, the menu populates correctly.
Activity code:
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;
}
}
}
Fragment code:
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);
}
}
Layout:
<?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>
Menu:
<?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>
Action menu being populated:
http://i.stack.imgur.com/QFMDd.png
Action menu not being populated:
http://i.stack.imgur.com/sH5Pp.png
回答1:
You should read this (by xcolw...)
Through experimentation it seems like the root cause is invalidateOptionsMenu getting called more than one without a break on the main thread to process queued up jobs. A guess - this would matter if some critical part of menu creation was deferred via a post, leaving the action bar in a bad state until it runs.
There are a few spots this can happen that aren't obvious:
calling viewPager.setCurrentItem multiple times for the same item
calling viewPager.setCurrentItem in onCreate of the activity. setCurrentItem causes an option menu invalidate, which is immediately followed by the activity's option menu invalidate
Workarounds I've found for each
Guard the call to viewPager.setCurrentItem
if (viewPager.getCurrentItem() != position)
viewPager.setCurrentItem(position);
Defer the call to viewPager.setCurrentItem in onCreate
public void onCreate(...) {
...
view.post(new Runnable() {
public void run() {
// guarded viewPager.setCurrentItem
}
}
}
After these changes options menu inside the view pager seems to work as expected. I hope someone can shed more light into this.
source http://code.google.com/p/android/issues/detail?id=29472
回答2:
The simple answer is to not use menus within fragments in the ViewPager.
If you do need to use menus within the fragments, what I suggest is loading the menu's through the onCreateOptionsMenu method in the parent Activity. Obviously you will need to be able to determine which menu to show.
I was able to achieve this by using class reflection.
You will also need to use the invalidateOptionsMenu method each time you switch pages. You will need a OnPageChangeListener to call this when the ViewPager changes pages.
回答3:
I also had same issue. In my case I have one activity with viewpager that contains two fragments, every fragment inflate its own action menu but fragment actions menu not shown.
View pager adapter code
public class ScreensAdapter extends FragmentPagerAdapter {
public TrackerScreensAdapter(Context context, FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return 2;
}
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position){
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
}
return fragment;
}
}
Activity on create
screensAdapter = new ScreensAdapter(this, getFragmentManager());
viewPager.setAdapter(screensAdapter);
This way my viewPager has two fragments, every fragment fire its own task in onActivityCreated, obtain data and draw its layout based on obtained data. Also every fragment has onCreateOptionsMenu
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
MyTask task = new MyTask();
task.setTaskListener(this);
task.execute();
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
}
Spent many times to solve this problem and figure out why fragment menu not shows.
All that I was need is
screenAdapter = new ScreenAdapter(this, getFragmentManager());
viewPager.post(new Runnable() {
public void run() {
viewPager.setAdapter(screenAdapter);
}
});
回答4:
First create a method in the sub class of FragmentPagerAdapter to get the current fragment
public SherlockFragment getFragment() {
return currentFragment;
}
@Override
public void onTabSelected(final Tab tab, FragmentTransaction ft) {
((SherlockFragmentActivity) mContext).invalidateOptionsMenu();
Fragment f = ((SherlockFragmentActivity) mContext)
.getSupportFragmentManager().findFragmentByTag(
makeFragmentName(tab.getPosition()));
currentFragment=(SherlockFragment) f;
}
Now override below methods in Main Actvity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (mTabsAdapter.getPositionOfTabSelected() != 0) {
menu.add("Read").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Write").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Clear").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Factory data reset").setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
return super.onCreateOptionsMenu(menu);
}
Now call the onOptionItemSelected from activity to fragment
@Override
public boolean onOptionsItemSelected(MenuItem item) {
mTabsAdapter.getFragment().onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
回答5:
I solved a very similar issue in which the Action bar icons assigned by the fragment inside of a ViewPager were disappearing onPause(). They would reappear when the Fragment came back into view and the user swiped left or right, but not immediately. The solution was calling notifyDataSetChanged() on the PagerAdapter in the onResume() method of the fragment.
@Override
public void onResume() {
mPagerAdapter.notifyDataSetChanged();
}
回答6:
I was having this problem with the Action Bar Items while I was using HorizontalScrollView to show the tabs but I changed to PagerTitleStrip and the problem was solved.
Perhaps this information can help someone else.
回答7:
In my case I traced the root cause of the issue to what I believe is a bug in FragmentStatePagerAdapter which is calling Fragment#setMenuVisibility to false and failing to properly set it back to true when it restores it's state.
Workarounds:
Use FragmentPagerAdapter instead of FragmentStatePagerAdapter
If you must use FragmentStatePagerAdapter, in your adapter subclass override setPrimaryItem like so:
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
//This is a workaround for a bug in FragmentStatePagerAdapter
Fragment currentItem = getItem(position);
if (currentItem != null) {
currentItem.setMenuVisibility(true);
currentItem.setUserVisibleHint(true);
}
}