Android:将数据(附加)传递给片段

Posted

技术标签:

【中文标题】Android:将数据(附加)传递给片段【英文标题】:Android: Pass data(extras) to a fragment 【发布时间】:2013-03-01 19:08:59 【问题描述】:

我是 android 编程新手,在将 Parcelable 的 ArrayList 传递给片段时遇到问题。 这是启动的 Activity(运行良好!),其中 feedlist 是可打包 Music 的 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 Music。

【问题讨论】:

第一步是要打开 LogCat 窗口,查看异常,看看是什么导致了 NullPointerException。如果您无法弄清楚,请将异常中的堆栈跟踪放入您的问题中,以便有人可以提供帮助。 BrianV:谢谢你的提示!这是我执行程序时得到的LogCat! pastebin.com/ycVcXLFf 看起来您的视图布局文件中有错误:** 原因:android.view.InflateException: Binary XML file line #10: Error inflating class fragment** 不,错误出在 ListView 的代码中,我确定。如果我在 ListMusicFragment 中创建 Music 对象的 ArrayList,则代码可以正常工作。无论如何,这是我的布局文件:pastebin.com/4DwHh1yk 【参考方案1】:

两件事。首先,我认为您没有添加要正确传递给片段的数据。您需要传递给片段的是捆绑包,而不是意图。例如,如果我想将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 方法后运行。如果您在 Activity 的 onCreate 方法期间将要检索的信息放入包中,则在片段的 onCreateView 期间将不存在该信息。尝试在onActivityCreated 中使用它,稍后再更新您的ListView 内容。

【讨论】:

简单的答案,真棒。复制了您的代码示例,效果很好! 那么......如果参数是由实现特定接口而不是原语的对象指定的呢? 如果你想使用对象,只需确保它们实现了Parcelable 接口。 Bundle 支持添加/获取Parcelable,所以你也可以发送这些没有问题。 在活动的 layout.xml 中定义片段时,您有工作流吗?在这种情况下,我相信android会实例化片段本身,这意味着你不能提供参数?我个人使用事件总线(otto)和生产者将数据从活动传递到片段。 当然 - 当您在 XML 中定义片段时,使用 android:tag 属性为该片段设置标签。在您的活动中,您可以使用 FragmentManager.findFragmentByTag() 来定位该片段,然后使用 FragmentTransaction 用您想要的方式配置的新片段替换 XML 片段。另一种方法是使用 findFragmentById 并简单地使用 XML 片段的 android:id 值。【参考方案2】:

我更喜欢Serializable = 没有样板代码。对于将数据传递给其他 Fragment 或活动 the speed difference to a Parcelable 无关紧要。

我也会始终为FragmentActivity 提供一个辅助方法,这样您就可以知道必须传递哪些数据。这是您的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);
    ...

【讨论】:

【参考方案3】:

由于内存中没有重复数据,我更喜欢捆绑包的原因很简单。它由片段的 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 方法创建片段的实例(您可以根据需要调用它),您可以传递列表的引用,而无需通过序列化创建片段实例的副本。这非常有用,因为如果您更改列表中的某些内容,您将在应用程序的其他部分获得它,当然,您使用的内存更少。

【讨论】:

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

以上是关于Android:将数据(附加)传递给片段的主要内容,如果未能解决你的问题,请参考以下文章

Android - 将搜索传递给片段

通过适配器在片段之间传递数据(Kotlin Android)

Android Java将变量从片段传递到活动[重复]

如何使用java将数据从片段传递到android中的另一个片段?

如何将选定的微调器 id 传递给片段

如何将数据从一个活动传递到android中的另一个活动片段? [复制]