tutorial - viewpager android




ViewPager PagerAdapter ne met pas à jour la vue (20)

Après beaucoup de recherches sur ce problème, j'ai trouvé une très bonne solution qui, selon moi, est la bonne façon de procéder. Pour l'essentiel, instantiateItem n'est appelé que lorsque la vue est instanciée et plus jamais à moins que la vue ne soit détruite (c'est ce qui se passe lorsque vous surchargez la fonction getItemPosition pour retourner POSITION_NONE). Au lieu de cela, vous devez enregistrer les vues créées et les mettre à jour dans l'adaptateur, générer une fonction get pour que quelqu'un d'autre puisse le mettre à jour ou une fonction set qui met à jour l'adaptateur (mon favori).

Donc, dans votre MyViewPagerAdapter, ajoutez une variable comme:

private View updatableView;

un dans votre instantiateItem:

 public Object instantiateItem(View collection, int position) {
        updatableView = new TextView(ctx); //My change is here
        view.setText(data.get(position));
        ((ViewPager)collection).addView(view);
        return view;
    }

Ainsi, de cette façon, vous pouvez créer une fonction qui mettra à jour votre vue:

public updateText(String txt)
{
    ((TextView)updatableView).setText(txt);
}

J'espère que cela t'aides!

J'utilise le ViewPager de la bibliothèque de compatibilité. Je l'ai reçu avec succès affichant plusieurs points de vue que je peux feuilleter.

Cependant, j'ai du mal à comprendre comment mettre à jour ViewPager avec un nouvel ensemble de vues.

J'ai essayé toutes sortes de choses comme appeler mAdapter.notifyDataSetChanged() , mViewPager.invalidate() même en créant un nouvel adaptateur chaque fois que je veux utiliser une nouvelle liste de données.

Rien n'a aidé, les textviews restent inchangés à partir des données d'origine.

Mise à jour: J'ai fait un petit projet de test et j'ai presque pu mettre à jour les vues. Je vais coller la classe ci-dessous.

Ce qui ne semble pas mettre à jour est cependant la 2ème vue, le 'B' reste, il devrait afficher 'Y' après avoir appuyé sur le bouton de mise à jour.

public class ViewPagerBugActivity extends Activity {

    private ViewPager myViewPager;
    private List<String> data;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        data = new ArrayList<String>();
        data.add("A");
        data.add("B");
        data.add("C");

        myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
        myViewPager.setAdapter(new MyViewPagerAdapter(this, data));

        Button updateButton = (Button) findViewById(R.id.update_button);
        updateButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                updateViewPager();
            }
        });
    }

    private void updateViewPager() {
        data.clear();
        data.add("X");
        data.add("Y");
        data.add("Z");
        myViewPager.getAdapter().notifyDataSetChanged();
    }

    private class MyViewPagerAdapter extends PagerAdapter {

        private List<String> data;
        private Context ctx;

        public MyViewPagerAdapter(Context ctx, List<String> data) {
            this.ctx = ctx;
            this.data = data;
        }

        @Override
        public int getCount() {
            return data.size();
        }

        @Override
        public Object instantiateItem(View collection, int position) {
            TextView view = new TextView(ctx);
            view.setText(data.get(position));
            ((ViewPager)collection).addView(view);
            return view;
        }

        @Override
        public void destroyItem(View collection, int position, Object view) {
             ((ViewPager) collection).removeView((View) view);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Parcelable saveState() {
            return null;
        }

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1) {
        }

        @Override
        public void startUpdate(View arg0) {
        }

        @Override
        public void finishUpdate(View arg0) {
        }
    }
}

Après des heures de frustration en essayant toutes les solutions ci-dessus pour surmonter ce problème et aussi essayer de nombreuses solutions sur d'autres questions similaires comme this , this et this qui a échoué avec moi pour résoudre ce problème et faire le ViewPager le pager avec le nouveau Fragment s. J'ai résolu le problème comme suit:

1) Rendre la classe ViewPager pour étendre FragmentPagerAdapter comme suit:

 public class myPagerAdapter extends FragmentPagerAdapter {

2) Créez un objet pour le ViewPager qui stocke le title et le fragment comme suit:

public class PagerItem {
private String mTitle;
private Fragment mFragment;


public PagerItem(String mTitle, Fragment mFragment) {
    this.mTitle = mTitle;
    this.mFragment = mFragment;
}
public String getTitle() {
    return mTitle;
}
public Fragment getFragment() {
    return mFragment;
}
public void setTitle(String mTitle) {
    this.mTitle = mTitle;
}

public void setFragment(Fragment mFragment) {
    this.mFragment = mFragment;
}

}

3) Faites en ViewPager le constructeur de ViewPager prenne mon instance de FragmentManager pour la stocker dans ma class comme suit:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mPagerItems = pagerItems;
}

4) Créez une méthode pour redéfinir les données de l' adapter avec les nouvelles données en supprimant directement tout le fragment précédent du fragmentManager lui-même pour que l' adapter définisse à nouveau le nouveau fragment de la nouvelle liste comme suit:

public void setPagerItems(ArrayList<PagerItem> pagerItems) {
    if (mPagerItems != null)
        for (int i = 0; i < mPagerItems.size(); i++) {
            mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
        }
    mPagerItems = pagerItems;
}

5) A partir du conteneur Activity ou Fragment , ne réinitialisez pas l'adaptateur avec les nouvelles données. Définissez les nouvelles données via la méthode setPagerItems avec les nouvelles données comme suit:

ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));

mPagerAdapter.setPagerItems(pagerItems);
mPagerAdapter.notifyDataSetChanged();

J'espère que ça aide.


C'est un problème horrible et je suis heureux de présenter une excellente solution; simple, efficace et efficace!

Voir ci-dessous, le code montre en utilisant un drapeau pour indiquer quand retourner POSITION_NONE

public class ViewPagerAdapter extends PagerAdapter
{
    // Members
    private boolean mForceReinstantiateItem = false;

    // This is used to overcome terrible bug that Google isn't fixing
    // We know that getItemPosition() is called right after notifyDataSetChanged()
    // Therefore, the fix is to return POSITION_NONE right after the notifyDataSetChanged() was called - but only once
    @Override
    public int getItemPosition(Object object)
    {
        if (mForceReinstantiateItem)
        {
            mForceReinstantiateItem = false;
            return POSITION_NONE;
        }
        else
        {
            return super.getItemPosition(object);
        }
    }

    public void setData(ArrayList<DisplayContent> newContent)
    {
        mDisplayContent = newContent;
        mForceReinstantiateItem = true;
        notifyDataSetChanged();
    }

}

Deux ans et demi après que le PO a posé sa question, cette question est encore, toujours, un problème. Il est évident que la priorité de Google sur ce n'est pas particulièrement élevé, donc plutôt que de trouver une solution, j'ai trouvé une solution de contournement. La grande percée pour moi était de découvrir quelle était la véritable cause du problème (voir la réponse acceptée dans ce post ). Une fois qu'il était évident que le problème était que les pages actives ne sont pas correctement actualisées, ma solution de contournement était évidente:

Dans mon fragment (les pages):

  • J'ai pris tout le code qui remplit le formulaire de onCreateView et le place dans une fonction appelée PopulateForm qui peut être appelée de n'importe où, plutôt que par le framework. Cette fonction tente d'obtenir la vue en cours en utilisant getView, et si elle est nulle, elle retourne simplement. Il est important que PopulateForm ne contienne que le code qui s'affiche - tout le code qui crée les écouteurs FocusChange et similaires est toujours dans OnCreate
  • Créez un booléen qui peut être utilisé comme un drapeau indiquant que le formulaire doit être rechargé. Le mien est mbReloadForm
  • Substituez OnResume () pour appeler PopulateForm () si mbReloadForm est défini.

Dans mon activité, où je fais le chargement des pages:

  • Allez à la page 0 avant de changer quelque chose. J'utilise FragmentStatePagerAdapter, donc je sais que deux ou trois pages sont affectées au maximum. Passer à la page 0 garantit que je n'ai jamais le problème sur les pages 0, 1 et 2.
  • Avant de vider l'ancienne liste, prenez sa taille (). De cette façon, vous savez combien de pages sont affectées par le bogue. Si> 3, réduisez-le à 3 - si vous utilisez un PagerAdapter différent, vous devrez voir combien de pages vous avez à traiter (peut-être tout?)
  • Rechargez les données et appelez pageAdapter.notifyDataSetChanged ()
  • Maintenant, pour chacune des pages affectées, voir si la page est active en utilisant pager.getChildAt (i) - cela vous indique si vous avez une vue. Si c'est le cas, appelez pager.PopulateView (). Sinon, définissez l'indicateur ReloadForm.

Après cela, lorsque vous rechargez un deuxième jeu de pages, le bogue entraînera toujours certains à afficher les anciennes données. Cependant, ils seront maintenant actualisés et vous verrez les nouvelles données - vos utilisateurs ne sauront pas que la page n'a jamais été incorrecte parce que cette actualisation aura lieu avant qu'ils voient la page.

J'espère que cela aide quelqu'un!


J'ai eu le même problème et ma solution est l' ViewPagerAdapter#getItemId(int position) de ViewPagerAdapter#getItemId(int position) :

@Override
public long getItemId(int position) {
    return mPages.get(position).getId();
}

Par défaut, cette méthode renvoie la position de l'élément. Je suppose que ViewPager vérifie si itemId été modifié et recrée la page seulement si c'était le cas. Mais la version non-overriden renvoie la même position que itemId même si la page est réellement différente, et ViewPager ne définit pas cette page est remplacée et doit être recréée.

Pour l'utiliser, long id est nécessaire pour chaque page. Normalement, on s'attend à ce qu'il soit unique, mais je suggère, pour ce cas, qu'il devrait juste être différent de la valeur précédente pour la même page. Ainsi, il est possible d'utiliser un compteur continu dans un adaptateur ou des entiers aléatoires (avec une distribution large) ici.

Je pense que c'est plus cohérent plutôt d'utiliser des Tags de vue mentionnés comme une solution dans ce sujet. Mais probablement pas pour tous les cas.


J'ai eu un problème similaire dans lequel j'avais quatre pages et une mise à jour des pages sur les trois autres. J'ai été capable de mettre à jour les widgets (SeekBars, TextViews, etc.) sur la page adjacente à la page en cours. Les deux dernières pages auraient des widgets non initialisés lors de l'appel de mTabsAdapter.getItem(position) .

Pour résoudre mon problème, j'ai utilisé setSelectedPage(index) avant d'appeler getItem(position) . Cela instancierait la page, me permettant d'être en mesure de modifier les valeurs et les widgets sur chaque page.

Après toute la mise à jour, j'utiliserais setSelectedPage(position) suivi de notifyDataSetChanged() .

Vous pouvez voir un léger scintillement dans le ListView sur la page de mise à jour principale, mais rien de notable. Je ne l'ai pas testé à fond, mais cela résout mon problème immédiat.


Je ne pense pas qu'il y ait un bug quelconque dans le PagerAdapter . Le problème est que comprendre comment cela fonctionne est un peu complexe. En regardant les solutions expliquées ici, il y a un malentendu et donc une mauvaise utilisation des vues instanciées de mon point de vue.

Les derniers jours, j'ai travaillé avec PagerAdapter et ViewPager , et j'ai trouvé ce qui suit:

La méthode notifyDataSetChanged() sur PagerAdapter notifiera seulement à ViewPager que les pages sous-jacentes ont été modifiées. Par exemple, si vous avez créé / supprimé dynamiquement des pages (en ajoutant ou en supprimant des éléments de votre liste), ViewPager devrait s'en charger. Dans ce cas, je pense que ViewPager détermine si une nouvelle vue doit être supprimée ou instanciée à l'aide des getItemPosition() et getCount() .

Je pense que ViewPager , après un appel notifyDataSetChanged() prend ses vues enfant et vérifie leur position avec le getItemPosition() . Si pour une vue enfant, cette méthode renvoie POSITION_NONE , ViewPager comprend que la vue a été supprimée, en appelant la fonction destroyItem() et en supprimant cette vue.

De cette façon, le fait de surcharger getItemPosition() pour retourner toujours POSITION_NONE est complètement faux si vous voulez seulement mettre à jour le contenu des pages, car les vues précédemment créées seront détruites et de nouvelles seront créées chaque fois que vous notifyDatasetChanged() . Cela peut sembler ne pas être si TextView juste pour quelques TextView , mais quand vous avez des vues complexes, comme ListViews peuplées à partir d'une base de données, cela peut être un vrai problème et un gaspillage de ressources.

Il existe donc plusieurs approches pour modifier efficacement le contenu d'une vue sans avoir à supprimer et à instancier à nouveau la vue. Cela dépend du problème que vous voulez résoudre. Mon approche consiste à utiliser la méthode setTag() pour toute vue instanciée dans la méthode setTag() . Ainsi, lorsque vous souhaitez modifier les données ou invalider la vue dont vous avez besoin, vous pouvez appeler la méthode findViewWithTag() sur ViewPager pour récupérer la vue précédemment instanciée et la modifier / utiliser comme vous le souhaitez sans avoir à supprimer / créer une nouvelle vue chaque fois que vous voulez mettre à jour une valeur.

Imaginez par exemple que vous ayez 100 pages avec 100 TextView et que vous souhaitiez uniquement mettre à jour une valeur périodiquement. Avec les approches expliquées précédemment, cela signifie que vous supprimez et instanciez 100 TextView sur chaque mise à jour. Cela n'a aucun sens...


Je poste juste cette réponse au cas où quelqu'un d'autre le trouve utile. Pour faire exactement la même chose, j'ai simplement pris le code source de ViewPager et PagerAdapter de la bibliothèque de compatibilité et l'ai compilé dans mon code (Vous devez trier toutes les erreurs et vous importer, mais c'est définitivement possible).

Ensuite, dans le CustomViewPager, créez une méthode appelée updateViewAt (int position). La vue elle-même peut être obtenue à partir de périphériques ArrayList définis dans la classe ViewPager (vous devez définir un ID pour les vues de l'élément instantiate et comparer cet ID avec la position dans la méthode updateViewAt ()). Ensuite, vous pouvez mettre à jour la vue si nécessaire.


Juste au cas où quelqu'un utiliserait l'adaptateur basé sur FragmentStatePagerAdapter (qui permettra à ViewPager de créer des pages minimum nécessaires pour l'affichage, au maximum 2 pour mon cas), la réponse de @ rui.araujo de l'écrasement de getItemPosition dans votre adaptateur ne causera pas de gaspillage significatif. peut être amélioré.

En pseudo code:

public int getItemPosition(Object object) {
    YourFragment f = (YourFragment) object;
    YourData d = f.data;
    logger.info("validate item position on page index: " + d.pageNo);

    int dataObjIdx = this.dataPages.indexOf(d);

    if (dataObjIdx < 0 || dataObjIdx != d.pageNo) {
        logger.info("data changed, discard this fragment.");
        return POSITION_NONE;
    }

    return POSITION_UNCHANGED;
}

Merci rui.araujo et Alvaro Luis Bustamante. Au début, j'essaie d'utiliser rui.araujo, parce que c'est facile. Cela fonctionne mais quand les données changent, la page se redessinera évidemment. C'est mauvais alors j'essaie d'utiliser le chemin d'Alvaro Luis Bustamante. C'est parfait. Voici le code:

@Override
protected void onStart() {
    super.onStart();
}

private class TabPagerAdapter extends PagerAdapter {
    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public boolean isViewFromObject(final View view, final Object object) {
        return view.equals(object);
    }

    @Override
    public void destroyItem(final View container, final int position, final Object object) {
        ((ViewPager) container).removeView((View) object);
    }

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final View view = LayoutInflater.from(
                getBaseContext()).inflate(R.layout.activity_approval, null, false);
        container.addView(view);
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        view.setTag(position);
        new ShowContentListTask(listView, position).execute();
        return view;
    }
}

Et quand les données changent:

for (int i = 0; i < 4; i++) {
    View view = contentViewPager.findViewWithTag(i);
    if (view != null) {
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        new ShowContentListTask(listView, i).execute();
    }
}

Toujours retourner POSITION_NONE est simple mais un peu inefficace car cela évoque l'instanciation de toutes les pages qui ont déjà été instanciées.

J'ai créé une bibliothèque ArrayPagerAdapter pour changer des éléments dans PagerAdapters dynamiquement.

En interne, les adaptateurs de cette bibliothèque ne renvoient POSITION_NONE sur getItemPosiition() que lorsque cela est nécessaire.

Vous pouvez modifier les éléments de manière dynamique en suivant cette bibliothèque.

@Override
protected void onCreate(Bundle savedInstanceState) {
        /** ... **/
    adapter = new MyStatePagerAdapter(getSupportFragmentManager()
                            , new String[]{"1", "2", "3"});
    ((ViewPager)findViewById(R.id.view_pager)).setAdapter(adapter);
     adapter.add("4");
     adapter.remove(0);
}

class MyPagerAdapter extends ArrayViewPagerAdapter<String> {

    public MyPagerAdapter(String[] data) {
        super(data);
    }

    @Override
    public View getView(LayoutInflater inflater, ViewGroup container, String item, int position) {
        View v = inflater.inflate(R.layout.item_page, container, false);
        ((TextView) v.findViewById(R.id.item_txt)).setText(item);
        return v;
    }
}

La bibliothèque Thils prend également en charge les pages créées par Fragments.


Toutes ces solutions ne m'ont pas aidé. J'ai donc trouvé une solution de travail: Vous pouvez setAdapter chaque fois, mais ce n'est pas suffisant. vous devriez le faire avant de changer d'adaptateur:

FragmentManager fragmentManager = slideShowPagerAdapter.getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
List<Fragment> fragments = fragmentManager.getFragments();
for (Fragment f : fragments) {
    transaction.remove(f);
}
transaction.commit();

et après ceci:

viewPager.setAdapter(adapter);

Vous pouvez mettre à jour dynamiquement tous les fragments, vous pouvez voir en trois étapes.

Dans votre adaptateur:

public class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mFragmentTags = new HashMap<Integer, String>();
}

// Returns total number of pages
@Override
public int getCount() {
    return NUM_ITEMS;
}

// Returns the fragment to display for that page
@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return FirstFragment.newInstance();
        case 1:
            return SecondFragment.newInstance();
        case 2:
            return ThirdFragment.newInstance();
        default:
            return null;
    }
}

// Returns the page title for the top indicator
@Override
public CharSequence getPageTitle(int position) {
    return "Page " + position;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        mFragmentTags.put(position, tag);
    }
    return object;
}

public Fragment getFragment(int position) {
    Fragment fragment = null;
    String tag = mFragmentTags.get(position);
    if (tag != null) {
        fragment = mFragmentManager.findFragmentByTag(tag);
    }
    return fragment;
}}

Maintenant dans votre activité:

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener{

MyPagerAdapter mAdapterViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ViewPager viewPager = (ViewPager) findViewById(R.id.vpPager);
    mAdapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(mAdapterViewPager);
    viewPager.addOnPageChangeListener(this);
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {

    Fragment fragment = mAdapterViewPager.getFragment(position);
    if (fragment != null) {
        fragment.onResume();
    }
}

@Override
public void onPageScrollStateChanged(int state) {

}}

Enfin dans votre fragment, quelque chose comme ça:

public class YourFragment extends Fragment {

// newInstance constructor for creating fragment with arguments
public static YourFragment newInstance() {

    return new YourFragment();
}

// Store instance variables based on arguments passed
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment, container, false);
}


@Override
public void onResume() {
    super.onResume();

    //to refresh your view
    refresh();

}}

Vous pouvez voir le code complet here .

Merci Alvaro Luis Bustamante.


ce qui fonctionnait pour moi allait viewPager.getAdapter().notifyDataSetChanged();

et dans l'adaptateur mettant votre code pour mettre à jour la vue à l'intérieur de getItemPosition comme si

@Override
public int getItemPosition(Object object) {

    if (object instanceof YourViewInViewPagerClass) { 
        YourViewInViewPagerClass view = (YourViewInViewPagerClass)object;
        view.setData(data);
    }

    return super.getItemPosition(object);
}

peut-être pas le moyen le plus correct d'aller à ce sujet mais il a fonctionné (le truc de return POSITION_NONE causé un accident pour moi, donc n'était pas une option)


For what it's worth, on KitKat+ it seems that adapter.notifyDataSetChanged() is enough to cause the new views to show up, provided that you've setOffscreenPageLimit sufficiently high. I'm able to get desired behavior by doing viewPager.setOffscreenPageLimit(2) .


I actually use notifyDataSetChanged() on ViewPager and CirclePageIndicator and after that I call destroyDrawingCache() on ViewPager and it works.. None of the other solutions worked for me.


I m using Tablayout with ViewPagerAdapter. For passing data between fragments or for communicating between fragments use below code which works perfectly fine and refresh the fragment when ever it appears. Inside button click of second fragment write below code.

b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            String text=e1.getText().toString(); // get the text from EditText

            // move from one fragment to another fragment on button click
            TabLayout tablayout = (TabLayout) getActivity().findViewById(R.id.tab_layout); // here tab_layout is the id of TabLayout which is there in parent Activity/Fragment
            if (tablayout.getTabAt(1).isSelected()) { // here 1 is the index number of second fragment i-e current Fragment

                LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
                Intent i = new Intent("EDIT_TAG_REFRESH");
                i.putExtra("MyTextValue",text);
                lbm.sendBroadcast(i);

            }
            tablayout.getTabAt(0).select(); // here 0 is the index number of first fragment i-e to which fragment it has to moeve

        }
    });

below is the code which has to be written in first fragment (in my case) ie in receiving Fragment.

MyReceiver r;
Context context;
String newValue;
public void refresh() {
    //your code in refresh.
    Log.i("Refresh", "YES");
}
public void onPause() {
    super.onPause();

    LocalBroadcastManager.getInstance(context).unregisterReceiver(r);
}
public void onResume() {
    super.onResume();
    r = new MyReceiver();
    LocalBroadcastManager.getInstance(getActivity()).registerReceiver(r,
            new IntentFilter("EDIT_TAG_REFRESH"));
} // this code has to be written before onCreateview()


 // below code can be written any where in the fragment
 private class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    PostRequestFragment.this.refresh();
        String action = intent.getAction();
        newValue=intent.getStringExtra("MyTextValue");
        t1.setText(newValue); // upon Referesh set the text
    }
}

I think I've made a simple way to notify of data set changes:

First, change a bit the way the instantiateItem function works:

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final View rootView = mInflater.inflate(...,container, false);
        rootView.setTag(position);
        updateView(rootView, position);
        container.addView(rootView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        mViewPager.setObjectForPosition(rootView, position);
        return rootView;
    }

for "updateView" , fill the view with all the data you wish to fill (setText,setBitmapImage,...) .

verify that destroyView works like this:

    @Override
    public void destroyItem(final ViewGroup container, final int position, final Object obj) {
        final View viewToRemove = (View) obj;
        mViewPager.removeView(viewToRemove);
    }

Now, suppose you need to change the data, do it, and then call the next function on the PagerAdapter :

    public void notifyDataSetChanged(final ViewPager viewPager, final NotifyLocation fromPos,
            final NotifyLocation toPos) {
        final int offscreenPageLimit = viewPager.getOffscreenPageLimit();
        final int fromPosInt = fromPos == NotifyLocation.CENTER ? mSelectedPhotoIndex
                : fromPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit
                        : mSelectedPhotoIndex + offscreenPageLimit;
        final int toPosInt = toPos == NotifyLocation.CENTER ? mSelectedPhotoIndex
                : toPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit
                        : mSelectedPhotoIndex + offscreenPageLimit;
        if (fromPosInt <= toPosInt) {
            notifyDataSetChanged();
            for (int i = fromPosInt; i <= toPosInt; ++i) {
                final View pageView = viewPager.findViewWithTag(i);
                mPagerAdapter.updateView(pageView, i);
            }
        }
    }

public enum NotifyLocation {
    MOST_LEFT, CENTER, MOST_RIGHT
}

For example if you wish to notify all of the views that are being shown by the viewPager that something has changed, you can call:

notifyDataSetChanged(mViewPager,NotifyLocation.MOST_LEFT,NotifyLocation.MOST_RIGHT);

C'est tout.



La réponse donnée par alvarolb est certainement la meilleure façon de le faire. S'appuyant sur sa réponse, un moyen facile de mettre en œuvre est de simplement stocker les vues actives par position:

SparseArray<View> views = new SparseArray<View>();

@Override
public Object instantiateItem(View container, int position) {
    View root = <build your view here>;
    ((ViewPager) container).addView(root);
    views.put(position, root);
    return root;
}

@Override
public void destroyItem(View collection, int position, Object o) {
    View view = (View)o;
    ((ViewPager) collection).removeView(view);
    views.remove(position);
    view = null;
}

Ensuite, une fois en notifyDataSetChanged méthode notifyDataSetChanged , vous pouvez actualiser les vues ...

@Override
public void notifyDataSetChanged() {
    int key = 0;
    for(int i = 0; i < views.size(); i++) {
       key = views.keyAt(i);
       View view = views.get(key);
       <refresh view with new data>
    }
    super.notifyDataSetChanged();
}

Vous pouvez réellement utiliser un code similaire dans notifyDataSetChanged et notifyDataSetChanged pour actualiser votre vue. Dans mon code, j'utilise exactement la même méthode.





android-viewpager