7

Używam ActionBarSherlock i ViewPagerIndicator do wyświetlania fragmentów jako kart. Jeden z tych fragmentów dodaje elementy do ActionBar:Awaria po dodaniu menu opcji elementu do paska działań z fragmentu, a następnie zmiana orientacji

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); 
} 

aw res/menu/fragment_maps.xml mam

<?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> 

Wszystko działa dobrze, dopóki ja obracać mój telefon. Po zmianie orientacji to menu staje się niedostępne (nic się nie dzieje po kliknięciu ikony). Następnie, jeśli ponownie obrócę telefon, pojawia się ten błąd:

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) 

Jakieś pomysły, jak go rozwiązać? Używam Android 2.3.6

Edycja: patrz test repository

+0

spróbować zadzwonić setHasOptionsMenu (true); od onActivityCreated nie z onCreate. – Leonidos

+0

@Leonidos To nie pomogło – Kuitsi

+0

Pokrewny problem: https://github.com/JakeWharton/ActionBarSherlock/issues/641 – pixel

Odpowiedz

3

myślę, To jest problem Kontekst. Dlatego występuje BadTokenException.

Istnieje wiele możliwości za tym wyjątkiem:

1) Może być używasz „this” jako kontekst odniesienia w pewnym miejscu, gdzie faktycznie potrzebuje YourActivity.this lub kontekstu aktywności macierzystej.

LUB

2) Z log-cat Jestem zgadywania, którą próbujesz wyświetlić okno Pop-up.

Problem może polegać na tym, że okno wyskakujące wyświetla się zbyt wcześnie (tj. Przed zakończeniem cyklu życia Activity). Poczekaj, aż zakończy się cykl życia aktywności.

Aby odroczyć wyświetlanie wyskakującego okienka, możesz polecić to link.

W-krótki ten problem wynika z poniższej użytkowej przypadku:

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.

Więc upewnij się, że nie ma żadnej sytuacji jak ta.

Mam nadzieję, że podpowie ci o rozwiązaniu problemu.

+0

Tworzę mój Fragment w ten sposób: http://stackoverflow.com/a/9245510/262462 I don ' • Mam jakiekolwiek odwołania do kontekstu w mojej klasie Fragmentu. – Kuitsi

+1

Drugi przypadek: Tak, jest to pewnego rodzaju popup. Po kliknięciu ikony menu w pasek akcji pojawi się menu rozwijane. Jak już powiedziałem, działa dobrze, dopóki nie zmieni się orientacja. Popraw, jeśli się mylę, ale aktywność rodzica restartuje się po zmianie orientacji. Czy Fragment uruchamia się samoczynnie w tym samym czasie? Dlaczego Fragment próbuje wyświetlić to menu w trybie rozszerzonym po zmianie orientacji? Byłoby mi zupełnie dobrze, gdyby w tym przypadku widoczna była tylko ikona menu. – Kuitsi

+0

Czy ktoś wie, co Android używa jako kontekst podczas tworzenia nowego fragmentu z konstruktorem, który nie ma argumentów? Zgodnie z dokumentami jest to takie samo jak 'Fragment.instantiate (Kontekst kontekstowy, String fname, Bundle args)' – Kuitsi

2

To jest Twój główną działalność:

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); 
     } 


    } 

To jest Twój 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(); 
      } 
     } 
    } 

Właśnie odbywa się w łatwy próbki, które można łatwo zrozumieć, w jaki sposób realizuje ActionBarSherlock i ViewPagerIndicator.

Chciałbym przesłać to na github, ale zrozumienie tego, jak to zrobić, może trochę potrwać, może nauczysz mnie później.

Następnie przesyłam to w 4shared. http://www.4shared.com/rar/zOWrvmyu/ViewpagerandSherlock.html

Jeśli masz jakiekolwiek pytania, zapytaj mnie później.

+0

Powinieneś podać więcej szczegółów tutaj, niezależnie. Nie wszyscy są skłonni pobrać próbkę z witryny hostingowej, a odpowiedzi za pomocą tylko linków i bez wyjaśnienia nie są dobre, jeśli ten link umrze. –

+0

@ A-C OK, zaktualizuję tutaj. – Marckaraujo

+1

Wygląda na to, że wypełniasz zawartość ActionBar bezpośrednio z działania. Muszę dodać to SubMenu przez Fragment, ponieważ mam wiele kart i to menu jest istotne tylko dla jednej karty. – Kuitsi

1

To zadziałało dla mnie, ale nie wiem, czy są jakieś efekty uboczne.

Dodaj do tego fragmentu jest onCreate

setRetainInstance(true); 

i to AndroidManifest.xml działalności zawierających fragment

android:configChanges="orientation" 
+0

Drugi nie jest potrzebny, ponieważ zachowuje się fragment w różnych zmianach konfiguracji. Wspomniany błąd ma coś wspólnego z oknami dialogowymi wewnątrz biblioteki sherlock, więc zachowanie instancji jest obejściem, ale nie naprawą. – pixel

+0

Wiem, że to tylko obejście problemu, więc nie zaznaczyłem tej odpowiedzi jako zaakceptowanej. :) Mogłem znaleźć jeden powrót z tego podejścia: 'android: showAsAction =" always | withText "' ten tekst jest czasem widoczny, a innym razem nie bez względu na orientację w danym momencie. Próbowałem 'invalidateOptionsmenu()', ale to nie pomogło. – Kuitsi

Powiązane problemy