web-dev-qa-db-fra.com

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

Je suis nouveau dans la programmation de Android et je rencontre des problèmes pour transmettre une ArrayList d’un Parcelable à un fragment. C’est l’activité qui est lancée (fonctionne bien!) Où feedlist est une ArrayList d'un paquetable Music.

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

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

La méthode fragment Activity onCreate ():

@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 de 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 est dans la ligne

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

Enfin, voici mon cours 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];
    }
};
}

Quand j'exécute ce code, le problème que je rencontre est un Java.lang.NullPointerException dans la méthode Fragment onCreateView (). J'apprécierais beaucoup si quelqu'un me dirigeait dans la bonne direction pour voir où j'échouais.

EDIT : Problème résolu: je devais simplement ajouter cette ligne à la méthode fragmentée Activity onCreate () (sinon l'objet getArguments () renverrait null):

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

Et ajoutez ceci au code de 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 Music.

76
pluralism

Deux choses. Premièrement, je ne pense pas que vous ajoutiez les données que vous voulez transmettre correctement au fragment. Ce que vous devez transmettre au fragment est un paquet, pas une intention. Par exemple, si je voulais envoyer une valeur int à un fragment, je créerais un ensemble, placerai le int dans cet ensemble, puis définirai cet ensemble comme un argument à utiliser lors de la copie. établi.

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

Deuxièmement, pour récupérer ces informations, vous devez 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 il n’est pas nécessaire de l’être. Cela dépend si vous définissez une valeur par défaut pour cet argument.

Enfin, je ne pense pas que vous puissiez faire cela dans onCreateView. Je pense que vous devez récupérer ces données dans la méthode onActivityCreated de votre fragment. Mon raisonnement est le suivant. onActivityCreated s'exécute une fois que l'activité sous-jacente a terminé sa propre méthode onCreate. Si vous placez les informations que vous souhaitez récupérer dans le bundle lors de la méthode onCreate de votre activité, elles n'existeront pas pendant le onCreateView de votre fragment. Essayez d’utiliser ceci dans onActivityCreated et mettez à jour votre contenu ListView ultérieurement.

180
Rarw

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 avec un Parcelable n'a pas d'importance.

Je voudrais aussi toujours fournir une méthode d'assistance pour un Fragment ou Activity, ainsi vous saurez 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);
    ...
}
2
artkoenig

Il y a une simple raison pour laquelle j'ai préféré le bundle en raison de l'absence de données dupliquées en mémoire. Il consiste en une méthode init public 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 le souhaitez), vous transmettez la référence de votre liste sans créer une copie par sérialisation de l’instance du fragment. Ceci est très utile car si vous modifiez quelque chose dans la liste, vous l'obtiendrez dans les autres parties de l'application et bien sûr, vous utiliserez moins de mémoire.

1
Ivan