将项目添加到Fragment的操作栏选项菜单后跟随方向更改后崩溃

时间:2012-11-20 12:23:58

标签: android android-layout android-fragments actionbarsherlock viewpagerindicator

我正在使用ActionBarSherlockViewPagerIndicator将片段显示为标签。其中一个片段将项添加到ActionBar:

private String[] mapNames;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    // init an String array `mapNames` which is used when populating submenu
    // ...
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    inflater.inflate(R.menu.fragment_maps, menu);

    SubMenu mapNamesMenu = menu.findItem(R.id.map_names).getSubMenu();
    mapNamesMenu.clear();
    for (int i=0; i<mapNames.length; i++) {
        mapNamesMenu.add(1, i, Menu.NONE, mapNames[i]);
    }

    super.onCreateOptionsMenu(menu, inflater);
}

并在res/menu/fragment_maps.xml我有

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/map_names"
        android:title="Maps"
        android:icon="@drawable/maps_32"
        android:showAsAction="always|withText">
        <menu>
            <item android:id="@+id/placeholder_maps" />
        </menu>
    </item>
</menu>

在旋转手机之前,一切正常。方向更改后,此菜单变得不可访问(单击图标时没有任何反应)。然后,如果我再次旋转手机,我会收到此错误:

FATAL EXCEPTION: main
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
at android.view.ViewRoot.setView(ViewRoot.java:532)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.view.Window$LocalWindowManager.addView(Window.java:424)
at android.widget.PopupWindow.invokePopup(PopupWindow.java:912)
at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:824)
at com.actionbarsherlock.internal.widget.IcsListPopupWindow.show(IcsListPopupWindow.java:226)
at com.actionbarsherlock.internal.view.menu.MenuPopupHelper.tryShow(MenuPopupHelper.java:129)
at com.actionbarsherlock.internal.view.menu.MenuPopupHelper.show(MenuPopupHelper.java:102)
at com.actionbarsherlock.internal.view.menu.ActionMenuPresenter.onSubMenuSelected(ActionMenuPresenter.java:273)
at com.actionbarsherlock.internal.view.menu.MenuBuilder.dispatchSubMenuSelected(MenuBuilder.java:263)
at com.actionbarsherlock.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:892)
at com.actionbarsherlock.internal.view.menu.ActionMenuView.invokeItem(ActionMenuView.java:510)
at com.actionbarsherlock.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:145)
at android.view.View.performClick(View.java:2494)
at android.view.View$PerformClick.run(View.java:9122)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3806)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)

任何想法如何解决?我正在使用Android 2.3.6

修改:请参阅test repository

3 个答案:

答案 0 :(得分:3)

我认为,这是一个上下文问题。这就是BadTokenException正在发生的原因。

此例外背后有很多可能性:

1)您可能正在使用“this”作为实际需要YourActivity.this或父活动上下文的某个地方的上下文引用。

2)从我猜测的log-cat开始,您正试图显示Pop-up窗口。

问题可能是,您过早显示弹出窗口(即在Activity生命周期完成之前)。 所以等到活动生命周期结束。

要推迟显示弹出窗口,您可以参考此link

简而言之,这个问题是由以下用例引起的:

  

活动的引用被传递给某个组件(例如   Toastalert dialogpop-up等),活动已被销毁但是   该组件仍然存在或试图使用被破坏的活动   上下文。

所以要确保没有这样的情况。

希望你能给你一些解决问题的暗示。

答案 1 :(得分:2)

这是您的主要活动:

public class BaseSampleActivity extends SherlockFragmentActivity {

        TestFragmentAdapter mAdapter;
        ViewPager mPager;
        PageIndicator mIndicator;

        protected ListFragment mFrag;



        @Override
        public void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);

            setContentView(R.layout.themed_titles);



//This adapter can load as many fragment as you want with different content, see later                  
                    mAdapter = new TestFragmentAdapter(getSupportFragmentManager());

                    mPager = (ViewPager)findViewById(R.id.pager);
                    mPager.setAdapter(mAdapter);
                    mPager.setCurrentItem(1);
                    mIndicator = (TitlePageIndicator)findViewById(R.id.indicator);
                    mIndicator.setViewPager(mPager);


        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            super.onCreateOptionsMenu(menu);
   //This show how to set up a Searhbar         
             SearchView searchView = new SearchView(getSupportActionBar().getThemedContext());
            searchView.setQueryHint("Procure pelo nome");
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

                @Override
                public boolean onQueryTextSubmit(String query) {

                    // TODO Auto-generated method stub
    //              Intent search = new Intent(getApplicationContext(), SearchableActivity.class);
    //              search.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    //              search.putExtra("query", query);
    //              startActivity(search);

                    return true;
                }

                @Override
                public boolean onQueryTextChange(String newText) {
                    // TODO Auto-generated method stub
                    return false;
                }
            });

            menu.add("Search")
                .setIcon(R.drawable.ic_search_inverse)
                .setActionView(searchView)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
   //This is how to set up a SubMenu         
            SubMenu subMenu1 = menu.addSubMenu("Action Item");
            subMenu1.add(0, 1, 0, "Sample");
            subMenu1.add(0, 2, 0, "Menu");
            subMenu1.add(0, 3, 0, "Sair");

            MenuItem subMenu1Item = subMenu1.getItem();
            subMenu1Item.setIcon(R.drawable.ic_title_share_default);
            subMenu1Item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);




            return true;
        }



        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
  //This is a switch case to do when the SubMenu is clicked.              
                case 1:
                    Toast.makeText(BaseSampleActivity.this, "Now "+item.getItemId(), Toast.LENGTH_SHORT).show();
                    return true;
                case 2:
                    Toast.makeText(BaseSampleActivity.this, "Now = "+item.getItemId(), Toast.LENGTH_SHORT).show();
                    return true;
                case 3:
                    Toast.makeText(BaseSampleActivity.this, "Now = "+item.getItemId(), Toast.LENGTH_SHORT).show();

                    return true;

            }
            return super.onOptionsItemSelected(item);
        }


    }

这是你的FragmentPagerAdapter:

 class TestFragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {
//Here you set up the title of each fragment, its in portuguese.
        protected static final String[] CONTENT = new String[] { "CATEGORIAS", "PRINCIPAL", "AS MELHORES", };
        protected static final int[] ICONS = new int[] {
                R.drawable.perm_group_calendar,
                R.drawable.perm_group_camera,
                R.drawable.perm_group_device_alarms,
        };

        private int mCount = CONTENT.length;

        public TestFragmentAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {Fragment f = null;
        switch(position){
        case 0:
        {
//Here you can set up a lot of diferent fragment content, here I just created a simple //arraylistfragment
        f = new ArrayListFragment();
        // set arguments here, if required
        Bundle args = new Bundle();
        args.putInt(ArrayListFragment.ARG_position, position);
        f.setArguments(args);
        break;
        }
        case 1:
        {
            f = new ArrayListFragment();
            // set arguments here, if required
            Bundle args = new Bundle();
            f.setArguments(args);
            break;
        }
        case 2:
        {   
            f = new ArrayListFragment();
            // set arguments here, if required
            Bundle args = new Bundle();
            f.setArguments(args);
            break;
        }   
        default:
          throw new IllegalArgumentException("not this many fragments: " + position);
        }


        return f;
        }

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

        @Override
        public CharSequence getPageTitle(int position) {
          return TestFragmentAdapter.CONTENT[position % CONTENT.length];
        }



        @Override
        public int getIconResId(int index) {
          return ICONS[index % ICONS.length];
        }

        public void setCount(int count) {
            if (count > 0 && count <= 10) {
                mCount = count;
                notifyDataSetChanged();
            }
        }
    }

我刚刚做了一个简单的示例,您可以轻松了解如何实现ActionBarSherlock和ViewPagerIndicator。

我想把它上传到github,但是需要一段时间才能理解如何去做,也许你可以稍后教我。

然后我在4shared上传这个。 http://www.4shared.com/rar/zOWrvmyu/ViewpagerandSherlock.html

如果您有任何疑问,请稍后再问我。

答案 2 :(得分:1)

这对我有用,但我不知道是否有一些副作用。

将此添加到Fragment的onCreate

setRetainInstance(true);

这是AndroidManifest.xml到包含Fragment的Activity

android:configChanges="orientation"