Android:データ(エクストラ)をフラグメントに渡す


83

私はAndroidプログラミングに不慣れで、ParcelableのArrayListをフラグメントに渡すときに問題が発生します。これは起動されるアクティビティです(うまく機能しています!)。ここで、フィードリストはパーセル可能な音楽のArrayListです。

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

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

フラグメントアクティビティ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はあるArrayListParcelable音楽。


最初のステップは、LogCatウィンドウを開き、例外を調べて、NullPointerExceptionの原因を確認することです。それがわからない場合は、例外からのスタックトレースを質問に入れてください。誰かが助けてくれます。
ブライアン

BrianV:ヒントをありがとう!これが、プログラムを実行したときに取得するLogCatです。pastebin.com/ycVcXLFf
多元主義

ビューレイアウトファイルにエラーがあるようです:**原因:android.view.InflateException:バイナリXMLファイルの行#10:クラスフラグメントのインフレーションエラー**
Brian

いいえ、エラーはListViewのコードにあります。確かにそうです。ListMusicFragmentでMusicオブジェクトのArrayListを作成すると、コードは問題なく機能します。とにかく、ここに私のレイアウトファイルがあります:pastebin.com/4DwHh1yk
多元主義

回答:


196

2つのこと。まず、フラグメントに渡したいデータを正しく追加しているとは思いません。フラグメントに渡す必要があるのはバンドルであり、インテントではありません。たとえば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 2013年

1
では...引数がプリミティブではなく特定のインターフェイスを実装するオブジェクトによって指定されている場合はどうなるでしょうか。
piotr

2
オブジェクトを使用する場合は、それらがParcelableインターフェースを実装していることを確認してください。Bundle追加/取得をサポートしているParcelableので、それらも問題なく送信できます。
rarw 2014

1
フラグメントがアクティビティのlayout.xmlで定義されている場合のワークフローはありますか?この場合、Androidはフラグメント自体をインスタンス化すると思います。つまり、引数を指定できませんか?個人的には、イベントバス(オットー)とプロデューサーを使用して、アクティビティからフラグメントにデータを渡します。
アレックホームズ

確かに-XMLでフラグメントを定義するときは、android:tag属性を使用してそのフラグメントのタグを設定します。アクティビティでは、FragmentManager.findFragmentByTag()を使用してそのフラグメントを見つけ、FragmentTransactionを使用してXMLフラグメントを希望どおりに構成された新しいフラグメントに置き換えることができます。もう1つのアプローチは、findFragmentByIdを使用し、XMLフラグメントのandroid:id値を使用することです。
rarw 2014

2

私が好むSerializable=定型コードなし。他のフラグメントまたはアクティビティにデータを渡す場合、aへの速度の違いParcelableは重要ではありません。

また、Fragmentまたはのヘルパーメソッドも常に提供し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

メモリ内に重複データがないため、バンドルを好んだ理由は簡単です。これは、フラグメントのinitpublicメソッドで構成されています

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メソッドで作成し(uは必要に応じて呼び出すことができます)、シリアル化によってフラグメントのインスタンスにコピーを作成せずに、リストの参照を渡します。これは非常に便利です。リスト内の何かを変更すると、アプリの他の部分でそれが取得され、もちろん、使用するメモリが少なくなるからです。


1
Androidではそれは間違った方法です。フラグメントの再作成(構成の変更(画面の回転)など)では、空のコンストラクターが呼び出され、すべてのパラメーターが失われるためです。推奨どおりに使用newInstancesetArgumentsてください。
CoolMind 2016年

-5

@Rarwによる素晴らしい答え。バンドルを使用して、あるフラグメントから別のフラグメントに情報を渡してみてください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.