2013-03-13 7 views
66

Ich bin neu in Android-Programmierung und ich habe Probleme beim Übergeben einer ArrayList eines Parcelable an ein Fragment. Dies ist die Aktivität, die gestartet wird (funktioniert gut!) feedlist ist eine ArrayList eines parcelable Music.Android: Pass Daten (Extras) zu einem Fragment

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

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

Das Fragment Aktivität onCreate() Methode:

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

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

Das Fragment Code:

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; 
} 
} 

denke ich, das Problem in der Leitung ist

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

Schließlich diese ist mein Musikunterricht:

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]; 
    } 
}; 
} 

Wenn ich diesen Code ausführen das Problem, das ich bekommen, ist eine java.lang.NullPointerException im Fragment onCreateView() -Methode. Ich würde mich sehr freuen, wenn jemand mich in die richtige Richtung zeigen würde, um zu sehen, wo ich versage.

EDIT: Problem gelöst: Ich brauchte nur diese Zeile mit dem Fragment Aktivität onCreate() -Methode (othwewise die getArguments() zurückkehren würde null) hinzuzufügen:

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

und fügen Sie diese an das Fragment Code:

@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)); 
    } 
} 

wo ist listMusics ein ArrayList von Parcelable Musik.

+0

Der erste Schritt besteht darin, das LogCat-Fenster zu öffnen, die Ausnahme zu betrachten und festzustellen, was die NullPointerException verursacht. Wenn Sie es nicht herausfinden können, dann setzen Sie den StackTrace von der Ausnahme in Ihre Fragen, damit jemand helfen kann. – Brian

+0

BrianV: Danke für den Tipp! Hier ist es das LogCat, das ich bekomme, wenn ich das Programm ausführe! http://pastebin.com/ycVcXLFf – pluralism

+0

Sieht aus, als hätten Sie einen Fehler in Ihrer Ansichts-Layoutdatei: ** Verursacht von: android.view.InflateException: Binär-XML-Dateizeile # 10: Fehler beim Aufblasen des Klassenfragments ** – Brian

Antwort

157

Zwei Dinge. Zuerst denke ich nicht, dass Sie die Daten hinzufügen, die Sie korrekt an das Fragment übergeben möchten. Was Sie an das Fragment übergeben müssen, ist ein Bündel, keine Absicht. Wenn ich zum Beispiel einen int Wert an ein Fragment senden möchte, würde ich ein Bündel erstellen, das int in dieses Paket einfügen und dann dieses Bündel als Argument festlegen, das beim Erstellen des Fragments verwendet werden soll.

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

Zweitens, um diese Informationen abzurufen, müssen Sie die Argumente an das Fragment gesendet bekommen. Sie extrahieren dann den Wert anhand des Schlüssels, mit dem Sie ihn identifiziert haben. Zum Beispiel in Ihrem Fragment:

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

Was Sie bekommen, ändert sich je nachdem, was Sie setzen. Auch der Standardwert ist normalerweise null, muss aber nicht sein. Es hängt davon ab, ob Sie einen Standardwert für dieses Argument festlegen.

Schließlich glaube ich nicht, dass Sie dies in onCreateView tun können. Ich denke, Sie müssen diese Daten innerhalb der onActivityCreated Methode Ihres Fragments abrufen. Meine Argumentation ist wie folgt. onActivityCreated wird ausgeführt, nachdem die zugrunde liegende Aktivität ihre eigene onCreate-Methode beendet hat. Wenn Sie die Informationen, die Sie abrufen möchten, innerhalb des Bündels während der onCreate-Methode Ihrer Aktivität platzieren, ist diese während der onCreateView Ihres Fragments nicht vorhanden.Versuchen Sie es in onActivityCreated und aktualisieren Sie später Ihre ListView Inhalte später.

+3

Einfache Antwort, super. Kopieren Sie Ihr Codebeispiel und es hat Spaß gemacht! – iamanyone

+1

Also ... was ist, wenn Argumente von Objekten spezifiziert werden, die bestimmte Schnittstellen implementieren und keine Primitiven? – Piotr

+2

Wenn Sie ein Objekt verwenden möchten, stellen Sie sicher, dass es die Parcelable-Schnittstelle implementiert. 'Bundle 'unterstützt das Hinzufügen/Abrufen von' Parcelable', so dass Sie diese auch problemlos senden können. – Rarw

1

Ich bevorzuge Serializable = kein Standardcode. Für die Weitergabe von Daten an andere Fragmente oder Aktivitäten the speed difference to a Parcelable spielt keine Rolle.

Ich würde auch immer eine Hilfsmethode für Fragment oder Activity bereitstellen, auf diese Weise wissen Sie immer, welche Daten übergeben werden müssen. Hier ein Beispiel für Ihre 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); 
    ... 
} 
1

Es gibt einen einfachen Grund, dass ich auf das Bündel bevorzugt aufgrund der keine doppelten Daten im Speicher. Es besteht aus einem init öffentliche Methode für das 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; 
} 
} 

In zwei Worten, Sie eine Instanz des Fragments ein von der init-Methode erstellen (u kann es nennen, wie u wünschen), die Referenz der Liste übergeben, ohne Erstellen Sie eine Kopie durch Serialisierung in der Instanz des Fragments. Dies ist sehr nützlich, denn wenn Sie etwas in der Liste ändern, erhalten Sie es in den anderen Teilen der App und natürlich verbrauchen Sie weniger Speicher.

+0

In Android ist es ein falscher Weg. Da bei der Fragment-Wiederherstellung (bei Konfigurationsänderung (Bildschirmrotation) und einigen anderen) ein leerer Konstruktor aufgerufen wird, gehen alle Parameter verloren. Verwenden Sie 'newInstance' und' setArguments' wie empfohlen. – CoolMind

-2

große Antwort von @Rarw. Verwenden Sie ein Bündel, um Informationen von einem Fragment zum anderen zu übertragen

Verwandte Themen