web-dev-qa-db-fra.com

Envoyer des données d'activité à fragmenter dans Android

J'ai deux cours. Le premier est l'activité, le second est un fragment où j'ai un EditText. En activité, j'ai une sous-classe avec async-task et en méthode doInBackground j'obtiens un résultat que je sauvegarde en variable. Comment puis-je envoyer cette variable de la sous-classe "mon activité" à ce fragment?

271
user1302569

À partir de l'activité, vous envoyez des données avec l'intention de:

Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);

et dans la méthode Fragment onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    String strtext = getArguments().getString("edttext");    
    return inflater.inflate(R.layout.fragment, container, false);
}
587
ρяσѕρєя K

Vous pouvez également accéder aux données d'activité à partir de fragment:

Activité:

public class MyActivity extends Activity {

    private String myString = "hello";

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

    public String getMyData() {
        return myString;
    }
}

fragment:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        MyActivity activity = (MyActivity) getActivity();
        String myDataFromActivity = activity.getMyData();
        return view;
    }
}
98
Ricardas

J'ai trouvé beaucoup de réponses ici @ stackoverflow.com mais c'est certainement la bonne réponse de:

"Envoi de données d'activité à fragmenter dans Android".

Activité:

        Bundle bundle = new Bundle();
        String myMessage = "Stackoverflow is cool!";
        bundle.putString("message", myMessage );
        FragmentClass fragInfo = new FragmentClass();
        fragInfo.setArguments(bundle);
        transaction.replace(R.id.fragment_single, fragInfo);
        transaction.commit();

fragment:

Lecture de la valeur dans le fragment

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Bundle bundle = this.getArguments();
        String myValue = bundle.getString("message");
        ...
        ...
        ...
        }

ou juste

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        String myValue = this.getArguments().getString("message");
        ...
        ...
        ...
        }
42
Jorgesys

Cette réponse est peut-être trop tard. mais ce sera utile pour les futurs lecteurs.

J'ai des critères. J'ai codé pour choisir le fichier d'intention. et le fichier sélectionné à transmettre à un fragment particulier pour un traitement ultérieur. J'ai beaucoup de fragments ayant la fonctionnalité de sélection de fichier. à ce moment-là, chaque vérification de la condition et obtenir le fragment et transmettre la valeur est assez dégoûtante. Donc, j'ai décidé de passer la valeur en utilisant l'interface.

Étape 1: Créez l'interface sur l'activité principale.

   public interface SelectedBundle {
    void onBundleSelect(Bundle bundle);
   }

Étape 2: Créer la référence SelectedBundle sur la même activité

   SelectedBundle selectedBundle;

Étape 3: créer la méthode dans la même activité

   public void setOnBundleSelected(SelectedBundle selectedBundle) {
       this.selectedBundle = selectedBundle;
   }

Étape 4: Nécessité d'initialiser la référence SelectedBundle qui sont tous des fragments ont besoin de la fonctionnalité de sélecteur de fichier.Vous placez ce code sur votre méthode fragment onCreateView(..)

    ((MainActivity)getActivity()).setOnBundleSelected(new MainActivity.SelectedBundle() {
          @Override
         public void onBundleSelect(Bundle bundle) {
            updateList(bundle);
        }
     });

Étape 5: onActivityResult de MainActivity, transmettez les valeurs aux fragments à l'aide de l'interface.

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent  data) {
       selectedBundle.onBundleSelect(bundle);
  }

C'est tout. Implémentez chaque fragment dont vous avez besoin sur FragmentClass. Vous êtes formidable. Vous avez fait. SENSATIONNEL...

15
Noorul

L’idée de base de Fragments (F) est de créer des composants d’UI auto-entretenus réutilisables dans les applications Android. Ces fragments sont contenus dans des activités et il existe un (meilleur) moyen commun de créer des voies de communication de A -> F et F-A. Il est indispensable de communiquer entre F-F via une activité, car seuls les fragments deviennent alors découplés et autonomes.

Ainsi, transmettre des données de A -> F sera identique à celui expliqué par ρяσѕρєя K. En plus de cette réponse, après la création des fragments dans une activité, nous pouvons également transmettre des données aux fragments appelant des méthodes dans Fragments.

Par exemple:

    ArticleFragment articleFrag = (ArticleFragment)
                    getSupportFragmentManager().findFragmentById(R.id.article_fragment);
    articleFrag.updateArticleView(position);
12
diyoda_

La meilleure approche consiste à appeler une instance de fragment et à envoyer des données à ce moment-là. chaque fragment a par défaut une méthode d'instance

Par exemple: si votre nom de fragment est MyFragment

alors vous appellerez votre fragment d'activité comme ceci:

getSupportFragmentManager().beginTransaction().add(R.id.container, MyFragment.newInstance("data1","data2"),"MyFragment").commit();

* R.id.container est un identifiant de mon FrameLayout

ainsi dans MyFragment.newInstance ("data1", "data2") vous pouvez envoyer des données à fragment et dans votre fragment, vous obtenez ces données dans MyFragment newInstance (String param1, String param2)

public static MyFragment newInstance(String param1, String param2) {
        MyFragment fragment = new MyFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

et ensuite dans onCreate méthode de fragment, vous obtiendrez les données:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

alors maintenant mParam1 ont data1 et mParam2 ont data2

maintenant vous pouvez utiliser ceci mParam1 et mParam2 dans votre fragment.

11
Pre_hacker

Si vous transmettez une référence au fragment (sous-classe concrète de) dans la tâche asynchrone, vous pouvez alors accéder directement au fragment.

Quelques façons de passer la référence au fragment dans la tâche asynchrone:

  • Si votre tâche asynchrone est une classe à part entière (class FooTask extends AsyncTask), transmettez votre fragment au constructeur.
  • Si votre tâche asynchrone est une classe interne, déclarez simplement une dernière variable de fragment dans l'étendue définie par la tâche asynchrone ou sous forme de champ de la classe externe. Vous pourrez y accéder depuis la classe interne.
7
Martin

J'aimerais ajouter pour les débutants que la différence entre les 2 réponses les plus votées est donnée par l'utilisation différente d'un fragment.

Si vous utilisez le fragment de la classe Java dans laquelle vous avez les données à transmettre, vous pouvez appliquer la première réponse pour transmettre des données:

Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);

Si toutefois vous utilisez par exemple le code par défaut fourni par Android Studio pour les fragments à onglets, ce code ne fonctionnera pas.

Cela ne fonctionnera pas même si vous remplacez le PlaceholderFragment par défaut par vos FragmentClasses et même si vous corrigez le FragmentPagerAdapter à la nouvelle situation en ajoutant un commutateur pour getItem () et un autre pour getPageTitle () (comme indiqué ici )

Attention: le clip mentionné ci-dessus contient des erreurs de code, ce que j'expliquerai plus tard, mais il est utile de voir comment passer du code par défaut au code éditable pour les fragments à onglets)! Le reste de ma réponse est beaucoup plus logique si vous considérez les classes Java et les fichiers xml de ce clip (représentatifs d'une première utilisation de fragments tabulés par un scénario débutant).

La principale raison pour laquelle la réponse la plus votée de cette page ne fonctionnera pas est que, dans ce code par défaut pour les fragments à onglets, les fragments sont utilisés dans une autre classe Java: FragmentPagerAdapter!

Ainsi, afin d’envoyer les données, vous êtes tenté de créer un bundle dans MotherActivity et de le transmettre dans FragmentPagerAdapter, à l’aide de la réponse n ° 2.

Seulement, c'est encore faux. ( Probablement vous pourriez le faire comme ça, mais c'est juste une complication qui n'est pas vraiment nécessaire ).

Je pense que la manière correcte/plus simple de le faire est de transmettre les données directement au fragment en question, à l’aide de la réponse n ° 2. Oui, il y aura un couplage étroit entre l'activité et le fragment, MAIS, pour les fragments à onglets, ce qui est plutôt attendu. Je vous conseillerais même de créer les fragments avec onglets dans la classe MotherActivity Java (en tant que sous-classes, car ils ne seront jamais utilisés en dehors de MotherActivity) - il est facile d'ajouter simplement dans la classe MotherActivity Java de nombreux fragments dont vous avez besoin comme ceci:

 public static class Tab1 extends Fragment {

    public Tab1() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
        return rootView;
    }
}.

Donc, pour transmettre des données de MotherActivity à un tel fragment, vous devez créer des chaînes/bundles privés au-dessus de l'activité onCreate de votre mère - que vous pouvez remplir avec les données que vous souhaitez transmettre aux fragments, puis les transmettre via un méthode créée après onCreate (appelée ici getMyData ()).

public class MotherActivity extends Activity {

    private String out;
    private Bundle results;

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

       // for example get a value from the previous activity
        Intent intent = getIntent();
        out = intent.getExtras().getString("Key");

    }

    public Bundle getMyData() {
        Bundle hm = new Bundle();
        hm.putString("val1",out);
        return hm;
    }
}

Et puis dans la classe fragment, vous utilisez getMyData:

public static class Tab1 extends Fragment {
        /**
         * The fragment argument representing the section number for this
         * fragment.
         */
        public Tab1() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
            TextView output = (TextView)rootView.findViewById(R.id.your_id_for_a_text_view_within_the_layout);

            MotherActivity activity = (MotherActivity)getActivity();

            Bundle results = activity.getMyData();
            String value1 = results.getString("val1");

            output.setText(value1);
            return rootView;
        }
    }

Si vous avez des requêtes de base de données, je vous conseille de les effectuer dans MotherActivity (et de transmettre leurs résultats sous forme de chaînes/entiers attachés à des clés dans un bundle, comme indiqué ci-dessus), comme dans les fragments à onglets, votre syntaxe deviendra plus complexe (getActivity) () par exemple, et getIntent devient getActivity (). getIntent), mais vous avez également la possibilité de faire ce que vous voulez.

Mon conseil aux débutants est de se concentrer sur de petites étapes. Tout d’abord, obtenez votre intention d’ouvrir une activité très simple, sans transmettre AUCUNE donnée. Est-ce que ça marche? Est-ce qu'il ouvre les onglets que vous attendez? Sinon pourquoi?

Commencez par cela, et en appliquant des solutions telles que celles présentées dans ce clip , voyez ce qui manque. Pour ce clip particulier, le fichier mainactivity.xml n'est jamais affiché. Cela va sûrement vous embrouiller. Mais si vous faites attention, vous verrez que, par exemple, le contexte (tools: context) est incorrect dans les fichiers de fragment xml. Chaque fragment XML doit pointer vers la classe de fragment correcte (ou sous-classe utilisant le séparateur $).

Vous verrez également que, dans la classe d'activité principale Java, vous devez ajouter tabLayout.setupWithViewPager (mViewPager) - juste après la ligne TabLayout tabLayout = (TabLayout) findViewById (R.id.tabs); sans cette ligne, votre vue n'est en réalité pas liée aux fichiers XML des fragments, mais elle affiche UNIQUEMENT le fichier xml de l'activité principale.

En plus de la ligne dans la classe d’activité principale Java, vous devez modifier les onglets dans le fichier XML d’activité principale pour les adapter à votre situation (par exemple, ajouter ou supprimer des éléments de tableau). Si vous ne disposez pas d'onglets dans le code XML d'activité principal, vous n'avez peut-être pas choisi le type d'activité correct lorsque vous l'avez créé (nouvelle activité - activité à onglets).

Veuillez noter que dans les 3 derniers paragraphes, je parle de la vidéo! Ainsi, lorsque je parle de l'activité principale XML, il s'agit de l'activité principale de la vidéo, qui correspond dans votre cas au fichier XML MotherActivity.

5
Adrian Stoica

A partir de l'activité, vous envoyez des données avec Bundle en tant que:

Bundle bundle = new Bundle();
bundle.putString("data", "Data you want to send");

// Your fragment
MyFragment obj = new MyFragment();
obj.setArguments(bundle);

Et dans la méthode onCreateView Fragment obtenir les données:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,`Bundle savedInstanceState) 
{
 String data = getArguments().getString("data");// data which sent from activity  
 return inflater.inflate(R.layout.myfragment, container, false);
}
4
Vijay

Très vieux post, j'ose toujours ajouter une petite explication qui m'aurait été utile.

Techniquement, vous pouvez directement définir des membres de n'importe quel type dans un fragment d'activité.
Alors pourquoi Bundle?
La raison est très simple: l’ensemble fournit une manière uniforme de gérer:
- création/ouverture d'un fragment
- reconfiguration (rotation de l'écran) - ajoutez simplement le paquet initial/mis à jour à outState dans onSaveInstanceState ()
- restauration de l'application après avoir été collectée en arrière-plan (comme pour la reconfiguration).

Vous pouvez (si vous aimez les expériences) créer une solution de contournement dans des situations simples, mais l'approche Bundle ne voit tout simplement pas la différence entre un fragment et mille sur un backstack - cela reste simple et direct.
C'est pourquoi la réponse de @ Elenasys est la solution la plus élégante et la plus universelle.
Et c'est pourquoi la réponse donnée par @ Martin a pièges

4
sberezin

Parfois, vous pouvez recevoir Intent dans votre activité et vous devez transmettre les informations à votre fragment de travail.
Les réponses données sont correctes si vous devez démarrer le fragment mais s'il fonctionne toujours, setArguments() n'est pas très utile.
Un autre problème survient si les informations transmises interagissent avec votre interface utilisateur. Dans ce cas, vous ne pouvez pas appeler quelque chose comme myfragment.passData(), car Android indiquera rapidement que seul le thread ayant créé la vue peut interagir.

Donc, ma proposition est d'utiliser un récepteur. De cette façon, vous pouvez envoyer des données de n’importe où, y compris l’activité, mais le travail sera effectué dans le contexte du fragment.

Dans votre fragment de onCreate():

protected DataReceiver dataReceiver;
public static final String REC_DATA = "REC_DATA";

@Override
public void onCreate(Bundle savedInstanceState) {


    data Receiver = new DataReceiver();
    intentFilter = new IntentFilter(REC_DATA);

    getActivity().registerReceiver(dataReceiver, intentFilter);
}

private class DataReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        int data= intent.getIntExtra("data", -1);

        // Do anything including interact with your UI
    }
}

Dans votre activité:

// somewhere
Intent retIntent = new Intent(RE_DATA);
retIntent.putExtra("data", myData);
sendBroadcast(retIntent);
3
fralbo

la meilleure approche pour envoyer des données d'une classe d'activité à un fragment passe par les méthodes setter. Comme

FragmentClass fragmentClass = new FragmentClass();
fragmentClass.setMyList(mylist);
fragmentClass.setMyString(myString);
fragmentClass.setMyMap(myMap);

et obtenir ces données de la classe facilement.

3
ssi-anik

Si un activity doit exécuter un fragment après l'initialisation, le moyen le plus simple consiste à faire en sorte que activity appelle une méthode sur l'instance fragment. Dans le fragment, ajoutez une méthode:

public class DemoFragment extends Fragment {
  public void doSomething(String param) {
      // do something in fragment
  }
}

puis dans la activity, accédez à la fragment à l'aide du gestionnaire fragment et appelez la method:

public class MainActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DemoFragment fragmentDemo = (DemoFragment) 
            getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
        fragmentDemo.doSomething("some param");
    }
}

puis le activity peut communiquer directement avec le fragment en appelant ce method.

2
user4813855

Vous pouvez créer une méthode statique publique dans fragment, où vous obtiendrez une référence statique de ce fragment, puis passerez des données à cette fonction et définirez ces données comme argument dans la même méthode. Vous obtiendrez des données via getArgument sur la méthode oncreate de fragment et définissez ces données sur local. variables.

1
M.Noman

La façon la plus intelligente et éprouvée de transmettre des données entre des fragments et une activité consiste à créer une variable, exemple:

class StorageUtil {
  public static ArrayList<Employee> employees;
}

Ensuite, pour passer des données de fragment en activité, nous le faisons dans la méthode onActivityCreated:

//a field created in the sending fragment
ArrayList<Employee> employees;

@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
         employees=new ArrayList();

       //Java 7 and above syntax for arraylist else use employees=new ArrayList<Employee>() for Java 6 and below

     //Adding first employee
        Employee employee=new Employee("1","Andrew","Sam","1984-04-10","Male","Ghanaian");
        employees.add(employee);

      //Adding second employee
       Employee employee=new Employee("1","Akuah","Morrison","1984-02-04","Female","Ghanaian");
         employees.add(employee);

        StorageUtil.employees=employees;
    }

Vous pouvez désormais obtenir la valeur de StorageUtil.employees de partout. Bonne chance!

1
Andrew Sam

Utilisez l'interface suivante pour communiquer entre activité et fragment

public interface BundleListener {
    void update(Bundle bundle);
    Bundle getBundle();
}

Ou utilisez la suite de cet écouteur générique pour une communication bidirectionnelle à l'aide d'une interface

 /**
 * Created by Qamar4P on 10/11/2017.
 */
public interface GenericConnector<T,E> {
    T getData();
    void updateData(E data);
    void connect(GenericConnector<T,E> connector);
}

méthode d'exposition par fragments

public static void show(AppCompatActivity activity) {
        CustomValueDialogFragment dialog = new CustomValueDialogFragment();
        dialog.connector = (GenericConnector) activity;
        dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
    }

vous pouvez transtyper votre contexte en GenericConnector dans onAttach(Context) aussi

dans votre activité

CustomValueDialogFragment.show(this);

dans ton fragment

...
@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        connector.connect(new GenericConnector() {
            @Override
            public Object getData() {
                return null;
            }

            @Override
            public void updateData(Object data) {

            }

            @Override
            public void connect(GenericConnector connector) {

            }
        });
    }
...
    public static void show(AppCompatActivity activity, GenericConnector connector) {
            CustomValueDialogFragment dialog = new CustomValueDialogFragment();
            dialog.connector = connector;
            dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
        }

Remarque: Ne l'utilisez jamais comme "".toString().toString().toString();.

1
Qamar

Ma solution est d'écrire une méthode statique à l'intérieur du fragment:

public TheFragment setData(TheData data) {
    TheFragment tf = new TheFragment();
    tf.data = data;
    return tf;
}

De cette façon, je suis sûr que toutes les données dont j'ai besoin sont à l'intérieur du fragment avant toute autre opération possible nécessitant son utilisation. En outre, il semble plus propre à mon avis.

0
Matteo

je suis tombé par hasard sur cette question, alors que la plupart des méthodes ci-dessus fonctionneront. Je veux juste ajouter que vous pouvez utiliser le bibliothèque de bus d'événements , en particulier dans les scénarios où le composant (Activité ou fragment) n'a pas été créé, il convient à toutes les tailles de Android projets et de nombreux cas d'utilisation. Je l'ai personnellement utilisé dans plusieurs projets que j'ai sur Playstore.

0
Joshua Majebi

J'ai rencontré un problème similaire lors de l'utilisation du dernier composant d'architecture de navigation. J'ai essayé tous les codes mentionnés ci-dessus en passant un paquet de mon activité d'appel à Fragment.

La meilleure solution, suivant les dernières tendances de développement sous Android, consiste à utiliser View Model (composant de Android Jetpack).

Créez et initialisez une classe ViewModel dans l'activité parente. Veuillez noter que ce ViewModel doit être partagé entre l'activité et le fragment.

À présent, dans la section onViewCreated () du fragment, initialisez le même ViewModel et configurez Observers pour écouter les champs ViewModel.

Voici un tutoriel utile et approfondi si vous en avez besoin.

https://medium.com/mindorks/how-to-communicate-between-fragments-and-activity-using-viewmodel-ca733233a51c

0
devDeejay