Android: 将数据(额外的)传递到一个片段

我是 Android 编程的新手,在把 Parcelable 的 ArrayList 传递给片段时遇到了问题。 这是启动的活动(运行良好!) ,其中 饲养员是一个可包装 音乐的数组列表。

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


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

片段 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());
}
}

碎片代码:

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

我觉得问题出在队伍里

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

最后是我的音乐课:

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

当我运行这个代码时,我得到的问题是 片段 onCreateView ()方法中的 java.lang. NullPointerException。 如果有人能给我指明正确的方向,让我看到自己的失败之处,我将不胜感激。

编辑 : 问题解决: 我只需要将这一行添加到片段 Activity onCreate ()方法中(否则 getArguments ()将返回 null) :

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

把这个添加到片段代码中:

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

其中,listMusics 是 Parcelable音乐的 ArrayList

134639 次浏览

Two things. First I don't think you are adding the data that you want to pass to the fragment correctly. What you need to pass to the fragment is a bundle, not an intent. For example if I wanted send an int value to a fragment I would create a bundle, put the int into that bundle, and then set that bundle as an argument to be used when the fragment was created.

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

Second to retrieve that information you need to get the arguments sent to the fragment. You then extract the value based on the key you identified it with. For example in your fragment:

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

What you are getting changes depending on what you put. Also the default value is usually null but does not need to be. It depends on if you set a default value for that argument.

Lastly I do not think you can do this in onCreateView. I think you must retrieve this data within your fragment's onActivityCreated method. My reasoning is as follows. onActivityCreated runs after the underlying activity has finished its own onCreate method. If you are placing the information you wish to retrieve within the bundle durring your activity's onCreate method, it will not exist during your fragment's onCreateView. Try using this in onActivityCreated and just update your ListView contents later.

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

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.