29

En la aplicación que estoy desarrollando estoy usando una ViewPager con fragmentos y cada fragmento construye su propio menú independientemente de todos los demás fragmentos en ViewPager.Elementos de acción del fragmento inicial de Viewpager no se muestran

El problema es que a veces los fragmentos inicializados por ViewPager de forma predeterminada (es decir, en su estado inicial) no están llenando sus elementos en el menú de elementos de acción. Lo que es peor es que este problema solo ocurre intermitentemente. Si deslizo la ViewPager lo suficiente para que los fragmentos se vuelvan a inicializar, al deslizar hacia atrás, el menú se llena correctamente.

Código de actividad:

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

código Fragmento:

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

} 

Diseño:

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

Menú:

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

menú Acción está poblando: http://i.stack.imgur.com/QFMDd.png

menú Acción no ser poblada: http://i.stack.imgur.com/sH5Pp.png

+0

acuerdo con Solarnz que parece no haber ninguna solución obvia. Creé una [aplicación de demostración] (https://github.com/snodnipper/page-flipper-race-condition/) que permite reproducir el problema de manera confiable. El mismo problema parece ser [informado en ActionBarSherlock] (https://github.com/JakeWharton/ActionBarSherlock/issues/351) y he planteado este [problema] (http://code.google.com/p/android/issues/detail? id = 29472) en el rastreador de problemas de Android. – snodnipper

Respuesta

21

Usted debe leer esto (por xcolw ...)

través de la experimentación parece que la causa de la raíz se llama invalidateOptionsMenu conseguir más de uno sin una rotura en el hilo principal para procesar trabajos en cola. Una suposición: esto importaría si una parte crítica de la creación del menú se aplazara a través de una publicación, dejando la barra de acción en mal estado hasta que se ejecute.

Hay algunos puntos Esto puede suceder que no son obvias:

  1. llamadas viewPager.setCurrentItem varias veces por el mismo artículo

  2. llamando viewPager.setCurrentItem en onCreate de la actividad. setCurrentItem provoca un menú invalidate opción, que es seguido inmediatamente por el menú de opciones de la actividad invalida

Soluciones provisionales que he encontrado para cada

  1. Guardia de la llamada a ViewPager.setCurrentItem

    if (viewPager.getCurrentItem() != position) 
        viewPager.setCurrentItem(position); 
    
  2. Defer la llamada a viewPager.setCurrentItem en onCreate

    public void onCreate(...) { 
        ... 
        view.post(new Runnable() { 
         public void run() { 
          // guarded viewPager.setCurrentItem 
         } 
        } 
    } 
    

Después de estas opciones de menú cambia dentro de la vista del localizador parece funcionar como se espera. Espero que alguien pueda arrojar más luz sobre esto.

fuentehttp://code.google.com/p/android/issues/detail?id=29472

+0

Excelente. Gracias. –

+0

Por favor, proporcione snipet completo sobre cómo usar esto con viewpager sin pestañas, no está claro para mí. Gracias. –

+0

No funcionó para mí. mViewPager.post (nueva Ejecutable() {@ Override public void run() { mViewPager.setAdapter (nueva FragPagerAdapter (getSupportFragmentManager(), MainActivity.this));! si (mViewPager.getCurrentItem() = 1) { mViewPager.setCurrentItem (1); } } }); –

8

La respuesta simple es no utilizar los menús dentro de los fragmentos en el ViewPager. Si necesita usar menús dentro de los fragmentos, lo que sugiero es cargar los menús a través del método onCreateOptionsMenu en la Actividad principal. Obviamente, deberá poder determinar qué menú mostrar.

Pude lograr esto usando la reflexión de clase. También necesitará usar el método invalidateOptionsMenu cada vez que cambie de página. Necesitará un OnPageChangeListener para llamar a esto cuando ViewPager cambie de página.

+0

¿Puedes compartir el código para eso? –

0

primer lugar crear un método en la clase sub de FragmentPagerAdapter para obtener el fragmento actual

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

Ahora anulan debajo de métodos principal de 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); 
} 

ahora la palabra onOptionItemSelected from activity al fragmento

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    mTabsAdapter.getFragment().onOptionsItemSelected(item); 
    return super.onOptionsItemSelected(item); 
} 
3

También tuve el mismo problema. En mi caso, tengo una actividad con viewpager que contiene dos fragmentos, cada fragmento infla su propio menú de acción pero el menú de acciones del fragmento no se muestra.

Ver código adaptador localizador

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

} 

Actividad en crear

screensAdapter = new ScreensAdapter(this, getFragmentManager()); 
    viewPager.setAdapter(screensAdapter); 

De esta manera mi ViewPager tiene dos fragmentos, cada fragmento de disparar su propia tarea en onActivityCreated, obtener datos y su diseño basado en datos obtenidos También cada fragmento tiene 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); 
} 

pasado muchas veces para resolver este problema y averiguar por qué no menú fragmento de espectáculos. todo lo que estaba necesidad es

screenAdapter = new ScreenAdapter(this, getFragmentManager()); 
    viewPager.post(new Runnable() { 
     public void run() { 
      viewPager.setAdapter(screenAdapter); 
     } 
    }); 
+0

¡Gracias! configurar el adaptador dentro del ejecutable lo resolvió para mí –

0

que resuelven un problema muy similar en el que los iconos de la barra de acciones asignadas por el fragmento en el interior de un ViewPager estaban desapareciendo onPause(). Volverían a aparecer cuando el Fragmento volviera a aparecer y el usuario se deslizara hacia la izquierda o hacia la derecha, pero no de inmediato. La solución llamaba a notifyDataSetChanged() en el PagerAdapter en el método onResume() del fragmento.

@Override 
public void onResume() { 
    mPagerAdapter.notifyDataSetChanged(); 
} 
0

que estaba teniendo este problema con los productos que la barra de acción, mientras que yo estaba usando HorizontalScrollView para mostrar las pestañas pero he cambiado a PagerTitleStrip y el problema se solucionó.

Quizás esta información puede ayudar a otros.

0

En mi caso rastreé la causa raíz del problema a lo que creo que es un error en FragmentStatePagerAdapter que llama a Fragment#setMenuVisibility en falso y falla al establecerlo correctamente en verdadero cuando restaura su estado.

Soluciones:

  1. Uso FragmentPagerAdapter en lugar de FragmentStatePagerAdapter

  2. Si tiene que usar FragmentStatePagerAdapter, en su adaptador subclase setPrimaryItem anulación de esta manera:

    @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); 
        } 
    } 
    
+0

Ninguno de estos enfoques funciona. – Proverbio

Cuestiones relacionadas