Jestem nowy w programowaniu na Androida i mam problemy podczas przekazywania ArrayList of a Parcelable do fragmentu. Jest to działanie, które jest uruchamiane (działa dobrze!), W którym lista kanałów jest tablicą listy plików muzycznych, które można sparować .
Intent in = new Intent(context, ListMusicsActivity.class);
in.putExtra("arrayMusic", feedList);
activity.startActivity(in);
Fragment metody 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());
}
}
Kod fragmentu:
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;
}
}
Myślę, że problem leży na linii
listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");
Wreszcie to moja klasa muzyczna:
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];
}
};
}
Kiedy uruchamiam ten kod, pojawia się problem java.lang.NullPointerException w metodzie Fragment onCreateView () . Byłbym wdzięczny, gdyby ktoś wskazał mi właściwy kierunek, aby zobaczyć, gdzie zawodzę.
EDYCJA : Problem rozwiązany: po prostu musiałem dodać tę linię do fragmentu metody Activity onCreate () (w przeciwnym razie getArguments () zwróci wartość null):
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, frag).commit();
I dodaj to do kodu fragmentu:
@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));
}
}
gdzie listMusics jest ArrayList
od Parcelable
muzyki.
źródło
Odpowiedzi:
Dwie rzeczy. Po pierwsze, nie sądzę, że poprawnie dodajesz dane, które chcesz przekazać do fragmentu. To, co musisz przekazać fragmentowi, to pakiet, a nie zamiar. Na przykład, gdybym chciał wysłać
int
wartość do fragmentu, utworzyłbym paczkę, umieściłbymint
w tej paczce, a następnie ustawiłbym ten pakiet jako argument, który ma być używany podczas tworzenia fragmentu.Bundle bundle = new Bundle(); bundle.putInt(key, value); fragment.setArguments(bundle);
Po drugie, aby odzyskać te informacje, musisz pobrać argumenty wysłane do fragmentu. Następnie wyodrębniasz wartość na podstawie klucza, który ją zidentyfikowałeś. Na przykład w Twoim fragmencie:
Bundle bundle = this.getArguments(); if (bundle != null) { int i = bundle.getInt(key, defaulValue); }
To, co otrzymujesz, zmienia się w zależności od tego, co umieścisz. Wartość domyślna to zazwyczaj,
null
ale nie musi. Zależy to od tego, czy ustawisz wartość domyślną dla tego argumentu.Wreszcie nie sądzę, że możesz to zrobić w
onCreateView
. Myślę, że musisz odzyskać te dane w ramachonActivityCreated
metody swojego fragmentu . Moje rozumowanie jest następujące.onActivityCreated
jest uruchamiany po zakończeniu działania bazowego własnejonCreate
metody. Jeśli umieszczasz informacje, które chcesz odzyskać w paczce podczasonCreate
metody swojej aktywności , nie będą one istnieć w czasie trwania Twojego fragmentuonCreateView
. Spróbuj użyć tego w programieonActivityCreated
i zaktualizujListView
zawartość później.źródło
Parcelable
interfejs.Bundle
obsługuje dodawanie / pobieranie,Parcelable
więc możesz je również wysłać bez problemu.Wolę
Serializable
= bez standardowego kodu. W przypadku przekazywania danych do innych fragmentów lub działań różnica szybkości względem aParcelable
nie ma znaczenia.Ja też zawsze dostarczenie sposobu dla pomocnika
Fragment
lubActivity
, w ten sposób zawsze wiesz, jakie dane mają być przekazywane. Oto przykład dla twojegoListMusicFragment
: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); ... }
źródło
Jest proste, dlaczego wolałem pakiet ze względu na brak zduplikowanych danych w pamięci. Składa się z publicznej metody init dla fragmentu
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; } }
W dwóch słowach, tworzysz instancję fragmentu za pomocą metody init (możesz ją wywołać jak chcesz) przekazujesz referencję swojej listy bez tworzenia kopii przez serializację do instancji fragmentu. Jest to bardzo przydatne, ponieważ jeśli zmienisz coś na liście, otrzymasz to w innych częściach aplikacji i oczywiście zużyjesz mniej pamięci.
źródło
newInstance
isetArguments
zgodnie z zaleceniami.świetna odpowiedź od @Rarw. Spróbuj użyć pakietu, aby przekazać informacje z jednego fragmentu do drugiego
źródło