Android:将数据(扩展名)传递给片段


83

我是Android编程的新手,将Parcelable的ArrayList传递给片段时遇到了问题。这是启动的活动(效果很好!),其中feedlist是可打包音乐的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];
    }
};
}

运行此代码时,出现的问题是Fragment 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是ArrayListParcelable音乐。


第一步将打开LogCat窗口,查看异常,并查看导致NullPointerException的原因。如果您无法解决问题,则将异常中的stacktrace放入您的问题中,否则有人可以提供帮助。
布莱恩(Brian)

BrianV:谢谢小费!这是执行程序时得到的LogCat!pastebin.com/ycVcXLFf
多元化

看起来您的视图布局文件中有一个错误:**原因:android.view.InflateException:二进制XML文件第10行:错误夸大了类片段**
Brian

不,错误是在ListView的代码中,我敢肯定。如果我在ListMusicFragment中创建Music对象的ArrayList,则代码可以正常工作。无论如何,这是我的布局文件:pastebin.com/4DwHh1yk
多元化

Answers:


196

两件事情。首先,我认为您没有正确添加要传递给片段的数据。您需要传递给片段的是捆绑包,而不是意图。例如,如果我想向int片段发送值,我将创建一个包,将其int放入该包中,然后将该束设置为创建片段时要使用的参数。

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

其次,要检索该信息,您需要将参数发送到片段。然后,根据您使用其标识的键来提取值。例如在您的片段中:

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

您得到的改变取决于您放置的内容。同样,默认值通常是,null但不一定是。这取决于是否为该参数设置默认值。

最后,我认为您无法在中执行此操作onCreateView。我认为您必须在片段的onActivityCreated方法内检索此数据。我的推理如下。onActivityCreated在基础活动完成其自己的onCreate方法之后运行。如果您要在活动onCreate方法期间将要检索的信息放入捆绑包中,则在片段的过程中该信息将不存在onCreateView。尝试在其中使用它,稍后再onActivityCreated更新您的ListView内容。


3
简单的答案,太棒了。复制了您的代码示例,并成功了!
iamanyone

1
那么...如果参数由实现特定接口而不是基元的对象指定,该怎么办?
Piotr

2
如果要使用对象,只需确保它们实现了Parcelable接口。Bundle支持添加/获取,Parcelable因此您也可以毫无问题地发送。
Rarw

1
在活动的layout.xml中定义片段时,您是否有工作流程?在这种情况下,我相信android会实例化片段本身,这意味着您无法提供参数?我个人使用事件总线(底部)和生产者将数据从活动传递到片段。
亚历克·福尔摩斯

当然-当您在XML中定义片段时,请使用android:tag属性为该片段设置标签。在您的活动中,您可以使用FragmentManager.findFragmentByTag()定位该片段,然后使用FragmentTransaction将XML片段替换为以所需方式配置的新片段。另一种方法是使用findFragmentById并仅使用XML片段的android:id值。
Rarw 2014年

2

我更喜欢Serializable=没有样板代码。对于将数据传递到其他片段或活动,速度差与aParcelable无关紧要。

我还将始终为Fragmentor提供帮助方法Activity,这种方式您始终知道必须传递哪些数据。这是您的示例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

有一个简单的原因,由于内存中没有重复数据,我之所以喜欢捆绑软件。它由片段的init公共方法组成

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

用两个词,您可以通过init方法(您可以根据需要调用它)创建片段的实例,然后传递列表的引用,而无需通过序列化到片段的实例来创建副本。这非常有用,因为如果您更改列表中的某些内容,您将在应用程序的其他部分得到它,当然,您将使用更少的内存。


1
在Android中,这是错误的方式。因为在片段重新生成时(在配置更改(屏幕旋转)等情况下),它将调用一个空的构造函数,并且所有参数都将丢失。使用newInstancesetArguments建议。
CoolMind '16

-5

@Rarw很好的答案。尝试使用捆绑包将信息从一个片段传递到另一个片段

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.