7

Я использую ActionBarSherlock и ViewPagerIndicator для отображения фрагментов в виде вкладок. Один из этих фрагментов добавляет элементы в 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

Edit: см test repository

+0

попытаться вызвать setHasOptionsMenu (истинный); from onActivityCreated не из onCreate. – Leonidos

+0

@ Leonidos Это не помогло – Kuitsi

+0

Связанная проблема: https://github.com/JakeWharton/ActionBarSherlock/issues/641 – pixel

ответ

3

Я думаю, Это проблема контекста. Вот почему происходит BadTokenException.

Есть много возможностей за исключением этого:

1) Может быть, вы используете «this» в качестве контекстной справки в каком-то месте, где он на самом деле нуждается в YourActivity.this или контексте родительской активности в.

ИЛИ

2) Из log-cat я угадываю, вы пытаетесь отобразить Pop-up окно.

Проблема может быть, вы показываете всплывающее окно слишком рано (т. Е. До завершения жизненного цикла Activity). Итак, дождитесь завершения жизненного цикла активности.

Чтобы отложить показ всплывающего окна, вы можете сослаться на этот link.

В-короткая эта проблема обусловлена ​​ниже потребительной случая:

An activity's reference is passed to the some component (i.e. like Toast , alert dialog , pop-up etc), and activity destroyed but that component is still alive or trying to use destroyed activity's context.

Поэтому убедитесь, что не существует какой-либо ситуации, как это.

Надеюсь, что это даст вам некоторое представление о решении проблемы.

+0

Создаю свой фрагмент следующим образом: http://stackoverflow.com/a/9245510/262462 Я не знаю, t есть ссылки на Context в моем классе Fragment. – Kuitsi

+1

Второй случай: Да, это своего рода всплывающее окно. Когда на панели действий отображается значок меню, появляется раскрывающееся меню. Как я уже сказал, он работает нормально, пока не изменится ориентация. Правильно, если я ошибаюсь, но родительская активность перезапускается при изменении ориентации. Перезапускается ли фрагмент одновременно в одно и то же время? Почему Fragment пытается отобразить это меню в расширенном режиме после изменения ориентации? Это было бы прекрасно для меня, если в этом случае видна только значок меню. – Kuitsi

+0

Кто-нибудь знает, что Android использует в качестве контекста, когда вы создаете новый фрагмент с конструктором, у которого нет аргументов? Согласно документам это то же самое, что и «Fragment.instantiate (контекст контекста, String fname, Bundle args)» – Kuitsi

2

Это ваш MainActivity:

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

Если у вас возникли вопросы, спросите меня позже.

+0

Вы должны указать более подробно здесь, независимо. Не все готовы загрузить ваш образец с сайта хостинга, а ответы с помощью только ссылок и без объяснений не стойкие, если эта ссылка умирает. –

+0

@ A-C Хорошо, я обновлю здесь. – Marckaraujo

+1

Похоже, вы заполняете содержимое ActionBar непосредственно из Activity. Мне нужно добавить SubMenu через Fragment, так как у меня есть несколько вкладок, и это меню относится только к одной вкладке. – Kuitsi

1

Это сработало для меня, но я не знаю, есть ли побочные эффекты.

Добавьте к этому фрагмент OnCreate

setRetainInstance(true); 

и это AndroidManifest.xml в операцию, содержащего фрагмент

android:configChanges="orientation" 
+0

Второй не нужен, так как вы сохраняете фрагмент во всех конфигурационных изменениях. Вы упомянули ошибку, связанную с диалоговыми окнами внутри библиотеки sherlock, поэтому сохранение экземпляра является обходным, но не исправлением. – pixel

+0

Я знаю, что это всего лишь обходной путь, поэтому я не отметил это как принятый ответ. :) Я, возможно, нашел один отступ от этого подхода: 'android: showAsAction =" always | withText ", этот текст иногда отображается, а в других случаях не имеет значения, какова ориентация на данный момент. Я попробовал 'invalidateOptionsmenu()', но это не помогло. – Kuitsi