web-dev-qa-db-fra.com

Comment mettre à jour-actualiser un fragment dans ViewPager par activité principale par programme

Je construis une application qui utilise Fragment et un seul MainActivity qui montre différents fragments dans le même ViewPager pour reproduire le comportement d'une application MVC typique.

Le problème est que je n'ai pas compris comment mettre à jour le fragment par programme pour mettre à jour le ViewPager avec les nouvelles modifications du fragment

Par exemple, j'ai ce Fragment qui montre un graphique, (dans mon intention) lorsque j'appelle setFragment(int interval, Point[] snodePoint) à partir du principal, le graphique doit être mis à jour dans ViewPager

public class LineFragment extends Fragment {
    static int interval;
    static Point snodePoints[];


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final View v = inflater.inflate(R.layout.fragment_linegraph, container,
                false);
        Bundle bundle = this.getArguments();
        ChartConfig cg = bundle.getParcelable("FragmentData");

        snodePoints = cg.getPoints();
        interval= cg.getInterval();
        Line l = new Line();

        for(int i=0; i<snodePoints.length; i++){
          LinePoint p = new LinePoint();
          Point sp=snodePoints[i];
          p.setX(sp.getX());
          p.setY(sp.getY());
          l.addPoint(p)
        }
        l.setColor(getResources().getColor(R.color.green));

        LineGraph li = (LineGraph) v.findViewById(R.id.linegraph);
        li.addLine(l);
        li.setRangeY(0, interval);
        li.setLineToFill(0);

        li.setOnPointClickedListener(new OnPointClickedListener() {

            @Override
            public void onClick(int lineIndex, int pointIndex) {
                // TODO Auto-generated method stub

            }

        });

        return v;
    }
}

En quelques mots, je dois

  • 1-créer un fragment basé sur les données reçues par l'activité principale.
  • 2-changer les données du fragment à chaque fois dans l'activité principale se produit quelque chose comme setFragment (...) avec de nouvelles données (générées toujours par le principal).

Comment pourrais-je faire ça?

L'activité principale avec le FragmentAdapter

public class MainActivity extends FragmentActivity {

ViewPager mViewPager;
MyFragmentAdapter mMyFragmentAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mViewPager = (ViewPager) findViewById(R.id.view_pager);
    final ActionBar bar = this.getActionBar();
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    LineFragment lineFrag = new LineFragment();
    BarFragment barFrag = new BarFragment();
    PieFragment pieFrag = new PieFragment();

    mMyFragmentAdapter = new MyFragmentAdapter(this, mViewPager);
    mMyFragmentAdapter.addTab(bar.newTab().setText("Line"), LineFragment.class,
            null, lineFrag);
    mMyFragmentAdapter.addTab(bar.newTab().setText("Bar"), BarFragment.class,
            null, barFrag);
    mMyFragmentAdapter.addTab(bar.newTab().setText("Pie"), PieFragment.class,
            null, pieFrag);
    mViewPager.setOffscreenPageLimit(mMyFragmentAdapter.getCount() - 1);
}

public static class MyFragmentAdapter extends FragmentStatePagerAdapter implements
        ActionBar.TabListener, ViewPager.OnPageChangeListener {

    private final MainActivity mContext;
    private final ActionBar mActionBar;
    private final ViewPager mViewPager;
    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
    private final ArrayList<Fragment> mFrag = new ArrayList<Fragment>();

    static final class TabInfo {
        private final Class<?> clss;
        private final Bundle args;

        TabInfo(Class<?> _class, Bundle _args) {
            clss = _class;
            args = _args;
        }
    }

    public MyFragmentAdapter(MainActivity activity, ViewPager pager) {
        super(activity.getSupportFragmentManager());
        mContext = activity;
        mActionBar = activity.getActionBar();
        mViewPager = pager;
        mViewPager.setAdapter(this);
        mViewPager.setOnPageChangeListener(this);
    }

    public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args,
            Fragment frag) {
        TabInfo info = new TabInfo(clss, args);
        tab.setTag(info);
        tab.setTabListener(this);
        mTabs.add(info);
        mFrag.add(frag);
        mActionBar.addTab(tab);
        notifyDataSetChanged();
    }

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

    @Override
    public Fragment getItem(int position) {
        TabInfo info = mTabs.get(position);
        Bundle args = new Bundle();
        ChartConfig cg = new ChartConfig(interval, snodePoint);
        args.putParcelable("FragmentData", cg);
        Fragment f = mFrag.get(position);
        f.setArguments(args);

        return f;
    }

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

    @Override
    public void onPageSelected(int position) {
        mActionBar.setSelectedNavigationItem(position);

    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

    public void onTabSelected(Tab tab, Android.app.FragmentTransaction ft) {
        Object tag = tab.getTag();
        for (int i = 0; i < mTabs.size(); i++) {
            if (mTabs.get(i) == tag) {
                mViewPager.setCurrentItem(i);
            }
        }
    }

    public void onTabUnselected(Tab tab, Android.app.FragmentTransaction ft) {
    }

    @Override
    public void onTabReselected(Tab tab, Android.app.FragmentTransaction ft) {
    }

}

}

La première fois que je crée le fragment, l'activité principale passe avec succès les paramètres au fragment par le biais de la fonction getItem(int position) remplacée, mais si j'essaie de modifier les données, également si j'essaie d'appeler notifyDataSetChanged() sur l'adaptateur mMyFragmentAdapter, rien ne se passe et les fragments dans ViewPager continuent d'utiliser les mêmes données transmises lors de la création.

MODIFIER

Après un code partiel vu dans une autre question sur la mise à jour du fragment, j'ai également essayé

public void update() {
        try{
            LineFragment fragment = 
                      (LineFragment) getSupportFragmentManager().findFragmentByTag(
                                   "Android:switcher:"+R.id.view_pager+":0");
                  if(fragment != null)
                  {
                     if(fragment.getView() != null) 
                     {

                        fragment.updateDisplay();
                     }
                  }
        }
        catch(RuntimeException e){
            e.printStackTrace();
        }

    }

En supposant que 0 est l'id du premier fragment Fragment-Tab (je ne suis pas sûr de ce type d'opération), mais fragment.updateDisplay(); n'est pas invoqué.

21
AndreaF

Dans votre adaptateur, remplacez getItemPosition

@Override
public int getItemPosition(Object object) {
    // POSITION_NONE makes it possible to reload the PagerAdapter
    return POSITION_NONE;
}

Après ça

viewPager.getAdapter().notifyDataSetChanged() 

devrait marcher.

46
luckyhandler

J'ai besoin de comprendre comment le Fragment peut faire passer les données par le principal, peut-être que je manque quelque chose mais vraiment je n'ai pas compris comment pourrais-je faire cela.

De cela, il semble que vous souhaitiez transmettre les données au moment de la création du Fragment. Si c'est ce que vous voulez, vous ne devez pas créer de constructeur personnalisé (et généralement pour un Fragment, vous ne devriez avoir que le constructeur sans argument par défaut (car la plate-forme en a besoin pour recréer le Fragment à certains moments)).

Au lieu de cela, vous devez soit passer les données dans un Bundle :

@Override
public Fragment getItem(int position) {
     switch (position) {
        //...
        Bundle args = new Bundle();
        args.put("a_string_representing_theKey", data)
        LineFragment f = new LineFragment();
        f.setArguments(args);
        return f;
        //...
     } 
}

Cela ne fonctionnera que si les données peuvent être placées dans un Bundle (voir la méthode put... De la classe Bundle, toutes les primitives + objets qui sont Parcelable ). Dans le fragment, vous pouvez ensuite récupérer les arguments à l'aide de getArguments().

Vous pouvez également faire en sorte que Fragment récupère les données directement à partir de Activity:

// in the lifecycle method where you want the data
((MainActivity)getActivity()).getDataForFragment(); // use the data

Par exemple, j'ai ce fragment qui montre un graphique, (dans mon intention) lorsque j'appelle setFragment (int interval, Point [] snodePoint) à partir du principal, le graphique doit être mis à jour dans ViewPager

Vous semblez vous contredire. Pour cela, utilisez le code de la question à laquelle j'ai lié, bien sûr, le simple fait d'appeler votre méthode setFragment() actuelle ne fera rien car vous mettez simplement à jour la valeur de deux variables, vous devrez informer l'interface utilisateur de le changement (comme appeler une autre méthode pour recréer la hiérarchie des vues, définir les nouvelles valeurs sur la vue graphique et appeler invalidate() etc).

Modifier:

Le code utilisé dans la question à laquelle j'ai lié devrait fonctionner, mais vous n'utilisez pas le bon code. Vous avez un FragmentStatePagerAdapter mais vous utilisez le code d'un FragmentPagerAdapter qui ne fonctionnera pas:

FragmentStatePagerAdapter a = (FragmentStatePagerAdapter) mViewPager.getAdapter();
LineFragment f = (LineFragment) a.instantiateItem(pager, thePositionYouWant);

Gardez à l'esprit que le code ci-dessus ne fonctionnera que pour le fragment visible plus 1 fragment de chaque côté, les autres fragments ne seront pas disponibles (et comme l'utilisateur ne les voit pas ou ne peut pas les déplacer immédiatement, ils ne devraient pas '' t être mis à jour).

3
Luksprog
#How to update-refresh Fragment in ViewPager by Main Activity programmatically
#after long struggle I find proper solution

tablayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {

                refreshTab(tab.getPosition());// create a method
                viewpager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
 private void refreshTab(int position) {
    switch (position) {
        case 0:


            break;
        case 1:

            CompaniesInterest comP1 = (CompaniesInterest) viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
            comP1.refreshpage();
            break;
        case 2:

            TotalSelectedCompanies toTal = (TotalSelectedCompanies) viewpager.getAdapter().instantiateItem(viewpager, viewpager.getCurrentItem());
            toTal.refreshpage();

    }
}
// Create a interface for refresh data for fragmen
public interface Refreshpage {
    void refreshpage();
}
// implements Refreshpage interface in both fragment TotalSelectedCompanies and CompaniesInterest
//
@Override`enter code here`
    public void refreshpage() {
        // do what you want to refresh 
    }
2
Shiv Kumar

très simple pour remplacer la méthode dans le fragment

@Passer outre

public void setUserVisibleHint(boolean isVisibleToUser) {

    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser){

        actionView();
    }
    else{
        //no
    }

}
2
Issac Balaji