web-dev-qa-db-fra.com

Actualisation d'une vue à l'intérieur d'un fragment

J'ai cherché les nombreuses questions qui ressemblent à celle-ci, mais je n'ai trouvé ma réponse dans aucune d'entre elles.

J'ai une activité qui a 3 onglets accessibles via la barre d'action. J'ai réalisé cela en ajoutant 3 fragments qui gonflent une vue personnalisée que j'ai faite en étendant la classe de vue.

Au moment où la base de données change, j'essaie de rafraîchir la vue dans mon onglet en appelant invalidate ()/postinvalidate (), mais cela ne fonctionne pas. Il en va de même pour appeler onCreateView du fragment comme autant d'autres options que j'ai envisagées.

Cependant, lorsque je vais dans un autre onglet et que je reviens en arrière, la modification a été apportée et ma vue est mise à jour comme il se doit.

Comment puis-je simuler la même chose qui se produit lors du passage à un autre onglet? Que se passe-t-il? J'ai essayé de regarder le cycle de vie du fragment (j'ai essayé d'appeler onCreateView ()) pour le comprendre, mais il ne veut tout simplement pas rafraîchir/redessiner comme il se doit.

Les données sont chargées correctement, car les données sont modifiées lorsque je passe à un autre onglet.

J'ai supprimé une partie du code car il n'est plus pertinent. J'ai implémenté des curseurs au lieu de mon propre modèle d'observateur pour notifier un changement. C'est ma principale activité en ce moment.

La question est de savoir ce que je dois faire maintenant si je veux redessiner la vue à l'intérieur de ces fragments. Si j'applique fragmentObject.getView (). Invalidate () cela ne fonctionne pas. J'ai le même problème qu'avant, mais maintenant mon observateur pour notifier un changement dans la base de données est correctement implémenté avec des chargeurs.

public class ArchitectureActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {

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

    ActionBar actionbar = getActionBar();
    actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    ActionBar.Tab EditTab = actionbar.newTab().setText("Edit");
    ActionBar.Tab VisualizeTab = actionbar.newTab().setText("Visualize");
    ActionBar.Tab AnalyseTab = actionbar.newTab().setText("Analyse");

    Fragment editFragment = new EditFragment();
    Fragment visualizeFragment = new VisualizeFragment();
    Fragment analyseFragment = new AnalyseFragment();

    EditTab.setTabListener(new MyTabsListener(editFragment));
    VisualizeTab.setTabListener(new MyTabsListener(visualizeFragment));
    AnalyseTab.setTabListener(new MyTabsListener(analyseFragment));

    actionbar.addTab(EditTab);
    actionbar.addTab(VisualizeTab);
    actionbar.addTab(AnalyseTab);

    ArchitectureApplication architectureApplication = (ArchitectureApplication)getApplicationContext();
    architectureApplication.initialize();

    getLoaderManager().initLoader(0, null, this);
    getLoaderManager().initLoader(1, null, this);
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    if (id == 0){
        return new CursorLoader(this, GraphProvider.NODE_URI , null, null, null, null);
    } else if (id == 1){
        return new CursorLoader(this, GraphProvider.ARC_URI , null, null, null, null);
    }
    return null;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    // Reloading of data, actually happens because when switching to another tab the new data shows up fine
    Log.e("Data", "loaded");
}

public void onLoaderReset(Loader<Cursor> loader) {
}
}
19
J. Maes

J'ai trouvé une solution de contournement pour rafraîchir la vue à l'intérieur de mon fragment. J'ai recréé (nouvelle CustomView) la vue à chaque mise à jour de la base de données. Après cela, j'appelle setContentView (vue CustomView). Cela ressemble plus à un hack, mais cela fonctionne et rien d'autre que j'ai essayé ne fait.

Bien que mon problème n'ait pas été résolu, j'ai donné la récompense à Alex Lockwood. Ses conseils sur les chargeurs ont amélioré mon application et cela m'a amené à continuer de chercher une solution que j'ai finalement trouvée.

3
J. Maes
  1. N'essayez pas d'appeler onCreateView() vous-même ... c'est une méthode de cycle de vie et ne devrait être appelée que par le framework.

  2. Fragments sont des composants d'interface utilisateur réutilisables. Ils ont leur propre cycle de vie, affichent leur propre vue et définissent leur propre comportement. Vous n'avez généralement pas besoin que votre Activity se mêle du fonctionnement interne d'un Fragment, car le comportement de Fragment doit être autonome et indépendant de tout Activity.

    Cela dit, je pense que la meilleure solution est que chacun de vos Fragment implémente l'interface LoaderManager.LoaderCallbacks<D>. Chaque Fragment initialisera un Loader (c'est-à-dire un CursorLoader si vous utilisez un ContentProvider soutenu par une base de données SQLite), et que Loader sera chargé (1) de charger les données sur un thread d'arrière-plan et (2) d'écouter les modifications de contenu apportées à la source de données et de fournir de nouvelles données à onLoadFinished() chaque fois qu'un changement de contenu se produit .

    Cette solution est meilleure que votre solution actuelle car elle est entièrement pilotée par les événements. Vous n'avez besoin d'actualiser la vue que lorsque les données sont livrées à onLoadFinished() (au lieu d'avoir à vérifier manuellement pour voir si la source de données a été modifiée à chaque fois que vous cliquez sur un nouvel onglet).

  3. Si vous êtes paresseux et que vous souhaitez simplement une solution rapide, vous pourrez peut-être vous en sortir en actualisant la vue dans la méthode onResume() de votre Fragment.

21
Alex Lockwood

J'ai eu un problème similaire (mais pas identique) que j'ai pu résoudre de la manière suivante:

Dans le fragment que j'ai ajouté

public void invalidate() {
    myView.post(new Runnable() {
        @Override
        public void run() {
            myView.invalidate();
        }
    });
}

et j'ai appelé cette méthode depuis l'activité lorsque je voulais rafraîchir la vue myView du fragment. L'utilisation de post () garantit que la vue n'est invalidée que lorsqu'elle est prête à être dessinée.

4
Jörg Eisfeld

J'ai eu le même problème. Ma solution était de détacher le fragment et de le rattacher.

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        Fragment f = getFragment(action);
        if(forceUpdate)
        {
            fragmentTransaction.detach(f);
            fragmentTransaction.attach(f);
        }
        fragmentTransaction.replace(R.id.mainFragment, f);
        fragmentTransaction.commit();
        currentAction = action;
2
mc.dev

La solution la plus rapide qui fonctionne pour moi:

 @Override
    public void onPause() {
        super.onPause();
        if (isRemoving() && fragmentView != null) {
            ((ViewGroup) fragmentView).removeAllViews();
        }
    }
2
georgehardcore