86 votes

Android : Transmettre des données (extras) à un fragment

Je suis nouveau dans la programmation Android et j'ai des problèmes en passant un ArrayList d'un Parcelable à un fragment. Voici l'activité qui est lancée (et qui fonctionne bien !) où liste d'alimentation est une liste de tableaux (ArrayList) d'un produit parcellaire Musique .

Intent in = new Intent(context, ListMusicsActivity.class);

in.putExtra("arrayMusic", feedList);
activity.startActivity(in);

La méthode onCreate() de l'activité du fragment :

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

    if(savedInstanceState != null)
    {
        ListMusicFragment frag = new ListMusicFragment();
        frag.setArguments(getIntent().getExtras());
    }
}

Le code du fragment :

public class ListMusicFragment extends SherlockFragment{

private ArrayList<Music> listMusics = new ArrayList<Music>();
private ListView listMusic;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
    Bundle savedInstanceState)
{
    listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");
    View view = inflater.inflate(R.layout.musiclistview, container, false);
    listMusic = (ListView) view.findViewById(R.id.musicListView);
    listMusic.setAdapter(new MusicBaseAdapter(getActivity(), listMusics));

    return view;
}
}

Je pense que le problème se situe au niveau de la ligne

listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");

Enfin, voici ma classe de musique :

public class Music implements Parcelable{

private String url;
private String artist;
private String title;
private String duration;
private String info_url;
private String lyrics;

public Music(String url, String artist, String title, 
    String duration, String lyrics, String info_url)
{
    this.url = url;
    this.artist = artist;
    this.title = title;
    this.duration = duration;
    this.lyrics = lyrics;
    this.info_url = info_url;
}

public Music(Parcel in)
{
    url = ParcelUtils.readString(in);
    artist = ParcelUtils.readString(in);
    title = ParcelUtils.readString(in);
    duration = ParcelUtils.readString(in);
    info_url = ParcelUtils.readString(in);
    lyrics = ParcelUtils.readString(in);
}

public String getUrl()
{
    return url;
}

public String getArtist()
{
    return artist;
}

public String getTitle()
{
    return title;
}

public String getDuration()
{
    return duration;
}

public String getLyrics()
{
    return lyrics;
}

public String getInfo()
{
    return info_url;
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags)
{
    ParcelUtils.writeString(dest, url);
    ParcelUtils.writeString(dest, artist);
    ParcelUtils.writeString(dest, title);
    ParcelUtils.writeString(dest, duration);
    ParcelUtils.writeString(dest, lyrics);
    ParcelUtils.writeString(dest, info_url);
}

public static final Parcelable.Creator<Music> CREATOR = 
    new Parcelable.Creator<Music>() {

    public Music createFromParcel(Parcel in)
    {
        return new Music(in);
    }

    public Music[] newArray(int size)
    {
        return new Music[size];
    }
};
}

Lorsque j'exécute ce code, le problème que j'obtiens est un java.lang.NullPointerException dans la méthode Fragment onCreateView() . J'apprécierais beaucoup que quelqu'un m'indique la bonne direction pour voir où je suis en train d'échouer.

EDIT : Problème résolu : Il m'a suffi d'ajouter cette ligne à la méthode onCreate() de l'activité fragment (sinon la méthode getArguments() renverrait null) :

getSupportFragmentManager().beginTransaction()
    .add(android.R.id.content, frag).commit();

Et ajoutez ceci au code du fragment :

@Override
    public void onActivityCreated(Bundle savedInstanceState)
{
    super.onActivityCreated(savedInstanceState);

    Bundle bundle = getArguments();
    if(bundle != null)
    {
        listMusics = bundle.getParcelableArrayList("arrayMusic");
        listMusic.setAdapter(new MusicBaseAdapter(getActivity(), listMusics));
    }
}

où, listMusics est un ArrayList de Parcelable La musique.

200voto

Rarw Points 3683

Deux choses. Premièrement, je ne pense pas que vous ajoutiez correctement les données que vous voulez passer au fragment. Ce que vous devez transmettre au fragment est un bundle, pas une intention. Par exemple, si je voulais envoyer un int à un fragment, je créerais une liasse, je mettrais l'élément int dans ce bundle, puis de définir ce bundle comme argument à utiliser lors de la création du fragment.

Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);

Ensuite, pour récupérer cette information, il faut obtenir les arguments envoyés au fragment. Vous extrayez ensuite la valeur en fonction de la clé avec laquelle vous l'avez identifiée. Par exemple, dans votre fragment :

Bundle bundle = this.getArguments();
if (bundle != null) {
    int i = bundle.getInt(key, defaulValue);
}

Ce que vous obtenez change en fonction de ce que vous mettez. De plus, la valeur par défaut est généralement null mais n'a pas besoin de l'être. Cela dépend si vous avez défini une valeur par défaut pour cet argument.

Enfin, je ne pense pas que vous puissiez le faire en onCreateView . Je pense que vous devez récupérer ces données dans le fragment onActivityCreated méthode. Mon raisonnement est le suivant. onActivityCreated s'exécute après que l'activité sous-jacente a terminé sa propre onCreate méthode. Si vous placez les informations que vous souhaitez récupérer dans la liasse au cours de l'activité de la onCreate il n'existera pas pendant la durée de vie de votre fragment. onCreateView . Essayez de l'utiliser dans onActivityCreated et mettez simplement à jour votre ListView plus tard.

1voto

Artjom Points 889

Je préfère Serializable = pas de code passe-partout. Pour transmettre des données à d'autres fragments ou activités la différence de vitesse à un Parcelable n'a pas d'importance.

Je fournirais également toujours une méthode d'aide pour une méthode Fragment o Activity De cette manière, vous savez toujours quelles données doivent être transmises. Voici un exemple pour votre ListMusicFragment :

private static final String EXTRA_MUSIC_LIST = "music_list";

public static ListMusicFragment createInstance(List<Music> music) {
    ListMusicFragment fragment = new ListMusicFragment();
    Bundle bundle = new Bundle();
    bundle.putSerializable(EXTRA_MUSIC_LIST, music);
    fragment.setArguments(bundle);
    return fragment;
}

@Override
public View onCreateView(...) { 
    ...
    Bundle bundle = intent.getArguments();
    List<Music> musicList = (List<Music>)bundle.getSerializable(EXTRA_MUSIC_LIST);
    ...
}

1voto

Ivan Points 938

Il y a une raison simple pour laquelle j'ai préféré la liasse en raison de l'absence de données dupliquées dans la mémoire. Il consiste en une méthode publique init pour le fragment

private ArrayList<Music> listMusics = new ArrayList<Music>();
private ListView listMusic;

public static ListMusicFragment createInstance(List<Music> music) {
    ListMusicFragment fragment = new ListMusicFragment();
    fragment.init(music);
    return fragment;
}

public void init(List<Music> music){
    this.listMusic = music;
}

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

    View view = inflater.inflate(R.layout.musiclistview, container, false);
    listMusic = (ListView) view.findViewById(R.id.musicListView);
    listMusic.setAdapter(new MusicBaseAdapter(getActivity(), listMusics));

    return view;
}
}

En deux mots, vous créez une instance du fragment et par la méthode init (vous pouvez l'appeler comme vous voulez) vous passez la référence de votre liste sans créer une copie par sérialisation à l'instance du fragment. C'est très utile car si vous changez quelque chose dans la liste, vous le retrouverez dans les autres parties de l'application et bien sûr, vous utiliserez moins de mémoire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X