7

Sto utilizzando ActionBarSherlock e ViewPagerIndicator per visualizzare Frammenti come schede. Uno di questi frammenti aggiunge elementi da ActionBar:Arresto anomalo dopo l'aggiunta di elementi al menu delle opzioni della barra azioni da Frammento seguito dal cambio di orientamento

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

e res/menu/fragment_maps.xml ho

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

Tutto funziona bene fino a quando ruoto il mio telefono. Dopo l'orientamento, questo menu diventa inaccessibile (non accade nulla quando si fa clic sull'icona). Quindi se faccio ruotare di nuovo il mio telefono ottengo questo errore:

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) 

Qualche idea su come risolverlo? Sto utilizzando Android 2.3.6

Edit: vedi test repository

+0

tenta di chiamare setHasOptionsMenu (true); da onActivityCreated non da onCreate. – Leonidos

+0

@Leonidos Non ha aiutato – Kuitsi

+0

Problema correlato: https://github.com/JakeWharton/ActionBarSherlock/issues/641 – pixel

risposta

3

credo, Questo è un problema di contesto. Ecco perché si sta verificando BadTokenException.

ci sono molte possibilità dietro questa eccezione:

1) Può essere che si sta utilizzando "this" come contesto di riferimento in qualche luogo in cui si ha bisogno in realtà YourActivity.this o contesto della attività di genitore.

O

2) Dal log-cat sto indovinando, si sta tentando di visualizzare una finestra Pop-up.

Il problema potrebbe essere, si sta visualizzando pop-up finestra troppo presto (vale a dire prima del ciclo di vita Activity completa.). Quindi aspetta fino al termine del ciclo di vita dell'attività.

Per posticipare la visualizzazione del popup, è possibile fare riferimento a questo link.

In breve questo problema è dovuto al caso d'uso di seguito:

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.

in modo da assicurarsi che non v'è alcuna situazione come questa.

Spero che questo ti dia qualche suggerimento su come risolvere il problema.

+0

Creo il mio frammento in questo modo: http://stackoverflow.com/a/9245510/262462 I don ' t avere riferimenti a Context nella mia classe Fragment. – Kuitsi

+1

Secondo caso: Sì, è una sorta di popup. Quando si fa clic sull'icona del menu nella barra delle azioni, viene visualizzato il menu a discesa. Come ho detto, sta funzionando bene fino a quando l'orientamento non cambia. Correggere se ho torto, ma l'attività dei genitori si riavvia al cambio di orientamento. Il frammento si riavvia contemporaneamente da solo? Perché Fragment sta cercando di visualizzare quel menu in modalità estesa dopo il cambio di orientamento? Sarebbe perfettamente ok per me, se solo l'icona del menu è visibile in quel caso. – Kuitsi

+0

Qualcuno sa cosa Android utilizza come contesto quando si crea un nuovo frammento con il costruttore che non ha argomenti? Secondo i documenti è lo stesso di 'Fragment.instantiate (Context context, String fname, Bundle args)' – Kuitsi

2

questa è la tua 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); 
     } 


    } 

Questo è il tuo 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(); 
      } 
     } 
    } 

Ho appena fatto un campione semplice che si può facilmente capire come implementa ActionBarSherlock e ViewPagerIndicator.

Mi piacerebbe caricare questo file su Github, ma ci vorrà un po 'per capire come farlo, forse puoi insegnarmi più tardi.

Quindi lo carico in 4shared. http://www.4shared.com/rar/zOWrvmyu/ViewpagerandSherlock.html

Se avete qualche domanda, chiedetelo più tardi.

+0

Qui dovresti dare più dettagli, a prescindere. Non tutti sono disposti a scaricare il campione da un sito di hosting e le risposte con solo collegamenti e senza spiegazione non stanno bene se quel collegamento muore. –

+0

@ A-C Ok, aggiornerò qui. – Marckaraujo

+1

Sembra che tu stia popolando i contenuti di ActionBar direttamente da Activity. Devo aggiungere quel sottomenu tramite Fragment, poiché ho più schede e quel menu è rilevante solo per una scheda. – Kuitsi

1

Questo ha funzionato per me ma non so se ci sono alcuni effetti collaterali.

Aggiungi questo al di Fragment onCreate

setRetainInstance(true); 

e questo per AndroidManifest.xml per attività contenente il frammento

android:configChanges="orientation" 
+0

Il secondo non è necessario poiché si mantiene il frammento tra le modifiche alla configurazione. Il bug che hai citato ha qualcosa in comune con le finestre di dialogo all'interno della libreria sherlock, quindi l'istanza di conservazione è una soluzione alternativa ma non una soluzione. – pixel

+0

So che questa è solo una soluzione, quindi non ho contrassegnato questo come risposta accettata. :) Potrei aver trovato un richiamo indietro da questo approccio: 'android: showAsAction =" always | withText "' quel testo è a volte visibile e altre volte non importa quale sia l'orientamento al momento. Ho provato 'invalidateOptionsmenu()' ma non ha aiutato. – Kuitsi

Problemi correlati