I'm new to Android programming and I'm having problems while passing an ArrayList of a Parcelable to a fragment. This is the Activity that is launched(working well!) where feedlist is an ArrayList of a parcelable Music.
Intent in = new Intent(context, ListMusicsActivity.class);
in.putExtra("arrayMusic", feedList);
activity.startActivity(in);
The fragment Activity onCreate() method:
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activitymusiclist);
if(savedInstanceState != null)
{
ListMusicFragment frag = new ListMusicFragment();
frag.setArguments(getIntent().getExtras());
}
}
The 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;
}
}
I think the problem is in the line
listMusics = (ArrayList<Music>) getArguments().getSerializable("arrayMusic");
Finally this is my Music class:
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];
}
};
}
When I run this code the problem I get is a java.lang.NullPointerException in the Fragment onCreateView() method. I would appreciate a lot if someone pointed me in the right direction to see where I am failing.
EDIT: Problem solved: I just needed to add this line to the fragment Activity onCreate() method(othwewise the getArguments() would return null):
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, frag).commit();
And add this to the 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));
}
}
where, listMusics is an ArrayList
of Parcelable
Music.
This question is related to
java
android
android-intent
nullpointerexception
great answer by @Rarw. Try using a bundle to pass information from one fragment to another
There is a simple why that I prefered to the bundle due to the no duplicate data in memory. It consists of a init public method for the 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 two words, you create an instance of the fragment an by the init method (u can call it as u want) you pass the reference of your list without create a copy by serialization to the instance of the fragment. This is very usefull because if you change something in the list u will get it in the other parts of the app and ofcourse, you use less memory.
I prefer Serializable
= no boilerplate code. For passing data to other Fragments or Activities the speed difference to a Parcelable
does not matter.
I would also always provide a helper method for a Fragment
or Activity
, this way you always know, what data has to be passed. Here an example for your 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);
...
}
Source: Stackoverflow.com