Problema extraño que refresca ViewPager con nuevo contenido:

Recibo datos de un servicio web que se analiza en un objeto de la clase Application , este objeto que en mi caso es una clase Report contiene una lista de Tabs que deben llenar el ViewPager . Por lo tanto, este informe se almacena en el parámetro currentReport en la clase Application.

Cada ficha debe ser una página en el ViewPager . Así que por primera vez cuando recibo los datos y los analizo, todo funciona perfectamente y el View Pager se rellena con los datos correctos y los presenta.

Mi problema se inicia cuando quiero obtener un nuevo Report del servidor y actualizar el ViewPager con los nuevos datos que se analizó en el parámetro currentReport .

Mi ViewPager es deslizar-capaz y tiene la navegación de las lengüetas, Tan cuando intento re-instantiate el ViewPager con el nuevo Report veo la cantidad derecha de las lengüetas agregadas al tabHost . Por alguna razón los fragmentos del nuevo informe superponiendo el fragmento del previos uno. Así que si el número de pestañas en el nuevo informe es mayor que las pestañas del informe anterior, puedo ver las pestañas del informe anterior además de parte de las nuevas (si por ejemplo en el primer informe tenía una pestaña y En el nuevo tengo 3 entonces veo el fragmento uno del anterior y el último 2 del siguiente).

He comenzado mi desarrollo de este tutorial y agregó el código de smoe a él: http://thepseudocoder.wordpress.com/2011/10/13/android-tabs-viewpager-swipe-able-tabs-ftw/

Este es mi código de actividad de la pestaña:

 public class TabsViewPagerFragmentActivity extends FragmentActivity implements ViewPager.OnPageChangeListener, TabHost.OnTabChangeListener { static final String TAG = TabsViewPagerFragmentActivity.class.getSimpleName(); private TabHost mTabHost; private ViewPager mViewPager; private HashMap<String, TabInfo> mapTabInfo; public ViewPagerAdapter mPagerAdapter; private TextView tvReportName, tvTabTitle; private Button bBackToParameters; private Dialog progressDialog; private SGRaportManagerAppObj application; private int numberOfTabs = 0; private Display display; public static final int POPUP_MARGIN = 6; LeftSideMenu leftSideMenu; public void NotifyTabActivityViewPagerAdapter() { mPagerAdapter.notifyDataSetChanged(); } public ViewPagerAdapter getTabActivityViewPagerAdapter() { return mPagerAdapter; } public ViewPager getTabActivityViewPager() { return mViewPager; } public void setCurrentTabTitle (String title) { tvTabTitle.setText(title); Log.d(TAG, "set tab title from activity: "+title); } /** * Maintains extrinsic info of a tab's construct */ private class TabInfo { private String tag; private Class<?> clss; private Bundle args; private Fragment fragment; TabInfo(String tag, Class<?> clazz, Bundle args) { this.tag = tag; this.clss = clazz; this.args = args; } } /** * A simple factory that returns dummy views to the Tabhost */ class TabFactory implements TabContentFactory { private final Context mContext; /** * @param context */ public TabFactory(Context context) { mContext = context; } /** (non-Javadoc) * @see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String) */ public View createTabContent(String tag) { View v = new View(mContext); v.setMinimumWidth(0); v.setMinimumHeight(0); return v; } } /** (non-Javadoc) * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle) */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); application = SGRaportManagerAppObj.getInstance(); display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); // Inflate the layout setContentView(R.layout.tabs_screen_activity_layout); tvTabTitle = (TextView) findViewById(R.id.tvTabName); tvReportName = (TextView)findViewById(R.id.tvReportName); tvReportName.setText(application.currentReport.getName()+ " - "); bBackToParameters = (Button) findViewById(R.id.bBackToParameters); leftSideMenu = (LeftSideMenu) findViewById(R.id.leftSideMenu); applyOnClickListenerToLeftSideMenu(); findViewById(R.id.showLeftMenuButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Display d = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); int width = d.getWidth(); View panel = findViewById(R.id.leftSideMenu); View appPanel = findViewById(R.id.appLayout); if (panel.getVisibility() == View.GONE){ appPanel.setLayoutParams(new LinearLayout.LayoutParams(width, LayoutParams.FILL_PARENT)); panel.setVisibility(View.VISIBLE); applyOnClickListenerToLeftSideMenu(); }else{ ToggleButton button = (ToggleButton) findViewById(R.id.showLeftMenuButton); button.setChecked(false); panel.setVisibility(View.GONE); } } }); // Initialise the TabHost progressDialog = DialogUtils.createProgressDialog(this, this.getString(R.string.populating_view_pager)); progressDialog.show(); if (SGRaportManagerAppObj.getInstance().parametersRepository.getParametersRepository().size() == 0) { bBackToParameters.setText(R.string.back_to_report_list); } this.initialiseTabHost(savedInstanceState); if (savedInstanceState != null) { mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); //set the tab as per the saved state } // Intialise ViewPager this.intialiseViewPager(); progressDialog.dismiss(); } /** (non-Javadoc) * @see android.support.v4.app.FragmentActivity#onSaveInstanceState(android.os.Bundle) */ protected void onSaveInstanceState(Bundle outState) { outState.putString("tab", mTabHost.getCurrentTabTag()); //save the tab selected super.onSaveInstanceState(outState); } /** * Initialise ViewPager */ public void intialiseViewPager() { List<Fragment> fragments = new Vector<Fragment>(); // TabInfo tabInfo = null; if (application.getCurrentDataSource().equals(DataSource.SSRS)) { numberOfTabs = application.currentReport.getTabsList().size(); } else if (application.getCurrentDataSource().equals(DataSource.SGRDL)) { numberOfTabs = application.currentReport.getODTabsList().size(); Log.d(TAG, "CURRENT REPORT FROM VIEW PAGER: "+ application.currentReport.toString()); } Log.d(TAG,"Current Tabs number from TabsViewPager activity: " +numberOfTabs); if (application.getCurrentDataSource().equals(DataSource.SSRS)) { for (int i = 0; i < numberOfTabs; i++) { Tab tempTab = application.currentReport.getTabsList().get(i); if (tempTab.getTabTemplateId() == 7) { GridFragment gridFragment = new GridFragment(tempTab); fragments.add(gridFragment); } else if (tempTab.getTabTemplateId() == 8) { NewChartFragment chartFragment = new NewChartFragment(tempTab, this); fragments.add(chartFragment); } } } else if (application.getCurrentDataSource().equals(DataSource.SGRDL)) { for (int i = 0; i < numberOfTabs; i++) { ODTab tempTab = application.currentReport.getODTabsList().get(i); if (tempTab.getTabType().equals(ODGrid.XML_GRID_ELEMENT)) { GridFragment gridFragment = GridFragment.newInstance(tempTab.getTabId()); fragments.add(gridFragment); } else if (tempTab.getTabType().equals(ODChart.XML_CHART_ELEMENT)) { NewChartFragment chartFragment = NewChartFragment.newInstance(tempTab.getTabId()); fragments.add(chartFragment); } } } Log.d(TAG, "Current report fragments set to adapter: "+fragments.toString()); /* if (this.mPagerAdapter == null) { this.mPagerAdapter = new ViewPagerAdapter(super.getSupportFragmentManager(), fragments); } else { this.mPagerAdapter.removeAllFragments(); this.mPagerAdapter.addFragmentsListToAdapter(fragments); } */ this.mPagerAdapter = new ViewPagerAdapter(super.getSupportFragmentManager(), fragments); this.mViewPager = (ViewPager)super.findViewById(R.id.pager); // this.mViewPager.setAdapter(null); this.mViewPager.setAdapter(this.mPagerAdapter); this.mViewPager.setOffscreenPageLimit(0); this.mViewPager.setOnPageChangeListener(this); Log.d(TAG, "Adapter initialized!"); } /** * Initialise the Tab Host */ public void initialiseTabHost(Bundle args) { mTabHost = (TabHost)findViewById(android.R.id.tabhost); /* //new edit if (mTabHost.getChildCount() > 0) { mTabHost.removeAllViews(); } */ mTabHost.setup(); TabInfo tabInfo = null; mapTabInfo = new HashMap<String, TabsViewPagerFragmentActivity.TabInfo>(); if (args != null) {} else { if (application.getCurrentDataSource().equals(DataSource.SSRS)) { int numberOfTabs = application.currentReport.getTabsList().size(); for (int i = 0; i < numberOfTabs; i++) { Tab tempTab = application.currentReport.getTabsList().get(i); if (tempTab.getTabTemplateId() == 7) { //GridFragment gridFragment = new GridFragment(tempTab); TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), GridFragment.class, args))); this.mapTabInfo.put(tabInfo.tag, tabInfo); } else if (tempTab.getTabTemplateId() == 8) { TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), NewChartFragment.class, args))); this.mapTabInfo.put(tabInfo.tag, tabInfo); } } } else if (application.getCurrentDataSource().equals(DataSource.SGRDL)) { int numberOfTabs = application.currentReport.getODTabsList().size(); for (int i = 0; i < numberOfTabs; i++) { ODTab tempTab = application.currentReport.getODTabsList().get(i); // Log.d(TAG,"Crashed Tab type: "+ tempTab.getTabType()); if (tempTab.getTabType().equals(ODGrid.XML_GRID_ELEMENT)) { //GridFragment gridFragment = new GridFragment(tempTab); TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), GridFragment.class, args))); this.mapTabInfo.put(tabInfo.tag, tabInfo); } else if (tempTab.getTabType().equals(ODChart.XML_CHART_ELEMENT)) { TabsViewPagerFragmentActivity.AddTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab "+String.valueOf(i)).setIndicator("Tab "+String.valueOf(i)), ( tabInfo = new TabInfo("Tab "+String.valueOf(i), NewChartFragment.class, args))); this.mapTabInfo.put(tabInfo.tag, tabInfo); } } } } // Default to first tab //this.onTabChanged("Tab1"); // mTabHost.setOnTabChangedListener(this); } /** * Add Tab content to the Tabhost * @param activity * @param tabHost * @param tabSpec * @param clss * @param args */ private static void AddTab(TabsViewPagerFragmentActivity activity, TabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo) { // Attach a Tab view factory to the spec ImageView indicator = new ImageView(activity.getBaseContext()); indicator.setPadding(10, 10, 10, 10); indicator.setImageResource(R.drawable.tab_select_icon_selector); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); lp.setMargins(10, 10, 10, 10); indicator.setLayoutParams(lp); tabSpec.setIndicator(indicator); tabSpec.setContent(activity.new TabFactory(activity)); tabHost.addTab(tabSpec); } /** (non-Javadoc) * @see android.widget.TabHost.OnTabChangeListener#onTabChanged(java.lang.String) */ public void onTabChanged(String tag) { //TabInfo newTab = this.mapTabInfo.get(tag); int pos = this.mTabHost.getCurrentTab(); this.mViewPager.setCurrentItem(pos); } /* (non-Javadoc) * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrolled(int, float, int) */ @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // TODO Auto-generated method stub } /* (non-Javadoc) * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageSelected(int) */ @Override public void onPageSelected(int position) { // TODO Auto-generated method stub this.mTabHost.setCurrentTab(position); } /* (non-Javadoc) * @see android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrollStateChanged(int) */ @Override public void onPageScrollStateChanged(int state) { // TODO Auto-generated method stub } 

Y este es mi código de adaptador:

 public class ViewPagerAdapter extends FragmentPagerAdapter { private List<Fragment> fragments; /** * @param fm * @param fragments */ public ViewPagerAdapter(FragmentManager fm, List<Fragment> fragments) { super(fm); this.fragments = fragments; } /* (non-Javadoc) * @see android.support.v4.app.FragmentPagerAdapter#getItem(int) */ @Override public Fragment getItem(int position) { return this.fragments.get(position); } /* (non-Javadoc) * @see android.support.v4.view.PagerAdapter#getCount() */ @Override public int getCount() { return this.fragments.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } 

Mi AsyncTask que analiza los datos y actualiza el ViewPager:

 public class ParseSGRDLReportDataAsyncTask extends AsyncTask<String, Object, Report>{ static final String TAG = ParseSGRDLReportDataAsyncTask.class.getSimpleName(); private Activity activity; private Exception exception; private ResponseHandler responseHandler = new ResponseHandler(); private SGRaportManagerAppObj application; private Dialog progressDialog; public ParseSGRDLReportDataAsyncTask(LoginScrActivity activity) { super(); this.activity = activity; } public ParseSGRDLReportDataAsyncTask(Activity currentActivity) { super(); this.activity = currentActivity; } public void onPreExecute() { application = SGRaportManagerAppObj.getInstance(); progressDialog = DialogUtils.createProgressDialog(activity, activity.getString(R.string.parse_data_dialog_message)); progressDialog.show(); } @Override protected Report doInBackground(String... params) { String ReportDataString = params[0]; try{ return DataAccessManager.parseSGRDLReportData(ReportDataString); } catch (Exception e) { exception = e; return null; } } @Override public void onPostExecute(Report result) { progressDialog.dismiss(); if (exception == null) { if (activity.getClass() == TabsViewPagerFragmentActivity.class) { application.currentReport = result; Log.d(TAG, "Current report parsed is: "+result); ((TabsViewPagerFragmentActivity)activity).intialiseViewPager(); ((TabsViewPagerFragmentActivity)activity).initialiseTabHost(null); ((TabsViewPagerFragmentActivity)activity).NotifyTabActivityViewPagerAdapter(); } else { responseHandler.handleProcessSGRDLReportDataResult(result, activity); } } else { processException(); } } private void processException() { Toast.makeText(activity, activity.getString(R.string.error_when_parsing_data), 3000).show(); } } 

Respuesta: Siguiendo el consejo de @Luksprog para todas las personas que tropiezan con el mismo problema este es el resultado final que funciona para mí, en el AsyncTask que necesitaba para añadir esto:

 if (activity.getClass() == TabsViewPagerFragmentActivity.class) { TabsViewPagerFragmentActivity tempActivity = ((TabsViewPagerFragmentActivity)activity); application.currentReport = result; Log.d(TAG, "Current report parsed is: "+result); List<Fragment> frags = tempActivity.getTabActivityViewPagerAdapter().getFragments(); // getter method in your adapter FragmentTransaction ft = tempActivity.getSupportFragmentManager().beginTransaction(); for (int i = 0; i < frags.size(); i++) { ft.remove(frags.get(i)); } ft.commit(); tempActivity.intialiseViewPager(); tempActivity.getTabHost().getTabWidget().removeAllViews(); tempActivity.initialiseTabHost(null); tempActivity.NotifyTabActivityViewPagerAdapter(); } 

Cuando los dos puntos principales son eliminar los fragmentos agregados anteriormente del FragmentManager / SupportFragmentManager usando un FragmentTransaction para mostrar el conjunto correcto de fragmentos en el ViewPager y quitar toda la vista del TabWidget antes de agregar nuevos.

No estoy seguro de que haya resuelto esto, si es que ignoro mi respuesta. El enlace proporcionado por Neron T es importante (más importante los consejos dados allí para no hacer referencia a los fragmentos del adaptador fuera).

Cuando establezca el adaptador la segunda vez con los nuevos datos, seguirá viendo los fragmentos antiguos debido a la forma en que se implementa FragmentPagerAdapter . Cuando vuelva a configurar el adaptador, el adaptador ejecutará primero el método destroyItem() en el que se destroyItem() su fragmento del ViewPager . A continuación, el adaptador ejecutará el método instantiateItem() . En este método, se realizará un chequeo en el FragmentManager para ver si alguno de los fragmentos anteriores aún no está disponible. Esta comprobación encontrará los fragmentos antiguos (por lo menos para las posiciones antiguas, por eso se obtienen nuevos fragmentos para la posición que no estaban en la situación anterior, no había ningún fragmento en ese momento) porque simplemente se separan de ViewPager (Pero todavía disponible en el FragmentManager través de findFragmentByTag() ). Si no se encuentra un fragmento en el FragmentManager se getItem() método getItem() , recuperando un fragmento de la lista.

Debería revisar su código para eliminar la referencia de lista a esos fragmentos, hay otras maneras de recuperar los fragmentos de ViewPager (no es ideal). Como una solución rápida, puede intentar eliminar manualmente los fragmentos antiguos del FragmentManager (justo antes de configurar el nuevo adaptador) para forzar el método ViewPager.instantiateItem() para llamar siempre a getItem() :

 if (activity.getClass() == TabsViewPagerFragmentActivity.class) { application.currentReport = result; Log.d(TAG, "Current report parsed is: "+result); ListFragment<Fragment> frags = ((ViewPagerAdapter)mViewPager.getAdapter()).getFragments(); // getter method in your adapter FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); for (int i = 0; i < mOldTmp.size(); i++) { ft.remove(frags.get(i)); } ft.commit(); ((TabsViewPagerFragmentActivity)activity).intialiseViewPager(); ((TabsViewPagerFragmentActivity)activity).initialiseTabHost(null); ((TabsViewPagerFragmentActivity)activity).NotifyTabActivityViewPagerAdapter(); } 

Esto no está probado, así que prueba y ver si funciona.

Hay dos soluciones para este problema:

Solución 1: fácil Ver aquí: https://stackoverflow.com/a/13467232/444324

Básicamente, es necesario agregar este código a su adaptador viewpager:

 @Override public int getItemPosition(Object object){ return PagerAdapter.POSITION_NONE; } 

Solución 2 – el recomendado se explica bien aquí: https://stackoverflow.com/a/8024557/444324

Voy a publicar algunos de mi código para que pueda tener alguna idea.

Inicialización del adaptador y establecerlo en el buscapersonas.

 vfPageContainer = (ViewPager)findViewById(R.id.vfPageContainer); mAdapter = new TestFragmentAdapter(this,getSupportFragmentManager()); vfPageContainer.setAdapter(mAdapter); 

Cada vez que llegan nuevos datos y llamo a continuación método:

Método updateUi ()

 private void updateUi() { for(int i=0 ; i < alDataPages.size() ; i++) { mAdapter.addFragment(TestFragment.newInstance(this)); } mAdapter.notifyDataSetChanged(); } 

En la clase TestFragmentAdapter existen r métodos para agregar y borrar los fragmentos de view-pager.

TestFragmentAdapter clase

 class TestFragmentAdapter extends FragmentStatePagerAdapter { private Context context; private ArrayList<Fragment> views = new ArrayList<Fragment>(); public TestFragmentAdapter(Context context,FragmentManager fm) { super(fm); this.context = context; views = new ArrayList<Fragment>(); } @Override public Fragment getItem(int position) { return views.get(position); } public void addFragment (Fragment v) { views.add(v); } public void clear() { for(int i = 0 ; i < views.size() ; i++) { views.clear(); } } @Override public int getCount() { return views.size(); } } 

Clase TestFragment

 public final static class TestFragment extends Fragment { private Context context; public void setContext(Context c) { context = c; } public static TestFragment newInstance(Context context) { TestFragment f = new TestFragment(); f.setContext(context); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { WebView webView_viewpage = new WebView(context); return webView_viewpage; } } 

Así que cuando los nuevos datos llegan antes que yo llamo el código abajo. Estoy quitando todas las vistas del adaptador y crea nuevo 1 y lo fijo al view-pager cada time.You también debe intentar esto en usted código que debe trabajar.

  mAdapter.clear(); // previously it was not working so i created new adapter and set it to the viewpager. mAdapter = new TestFragmentAdapter(this,getSupportFragmentManager()); vfPageContainer.setAdapter(mAdapter); 

Espero que esta ayuda para usted y usted encontrará la solución.

  • Calendario y PagerAdapter - Vistas ilimitadas
  • ¿Por qué getCount se llama tantas veces en PagerAdapter?
  • Hacer ViewPager rápido con la resistencia más corta
  • Manejo del cambio de orientación con ViewPager + FragmentPagerAdapter
  • Deslizar entre las actividades de Android como con ViewPager
  • ViewPager con Fragmentos que contienen TableLayouts se carga lentamente:
  • Guardar estado de fragmento en ViewPager
  • Fragment onResume () no se llama cuando se utiliza FragmentPagerAdapter
  • Android: Fragment y ViewPager comienza siempre en la primera posición
  • ¿Alguien sabe cómo usar PagerTitleStrip en Android
  • Cómo reemplazar View Pager ver completamente con un nuevo Fragmento en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.