2

I'm learning android fundamentals and I came across this problem while creating my first app. I have an activity which passes on data to a fragment. The OnCreate method of the activity has a block like this:

    if(savedInstanceState == null){
        DetailActivityFragment detailFrag = DetailActivityFragment.newInstance(movieId);
        getSupportFragmentManager().beginTransaction().add(android.R.id.content,detailFrag).commit();
    }

    setContentView(R.layout.activity_detail);

At the fragment (activity_detail) if I perform getParameters(), I receive null. By playing around, I found that if I remove setContentView method from the snippet above, the fragment shows up with the data. Any ideas as to why that was a problem? Thanks!

Edit: Here is my static newInstance method in the fragment

public static DetailActivityFragment newInstance(String id) {
    DetailActivityFragment fragment = new DetailActivityFragment();
    Bundle args = new Bundle();
    args.putString(Intent.EXTRA_TEXT, id);
    fragment.setArguments(args);
    return fragment;
}

Here's my fragment from the layout activity_detail:

<fragment android:name="app.appone.DetailActivityFragment"
android:id="@+id/fragment_detail"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
shark1608
  • 649
  • 11
  • 24
  • please call setContentView(R.layout.activity_detail); above declaration of fragment – Amarjit Aug 12 '15 at 08:45
  • That's what I had thought the first time. That doesn't work – shark1608 Aug 12 '15 at 08:46
  • It would help to see the code for your `newInstance()` method, just to ensure `setArguments()` is being called on your new fragment correctly. – PPartisan Aug 12 '15 at 08:48
  • probably you forget to set arguments to your new fragment which you create DetailActivityFragment.newInstance – savepopulation Aug 12 '15 at 08:52
  • 1
    added my `newInstance()` method in the question – shark1608 Aug 12 '15 at 08:54
  • Your `newInstance()` method looks ok. I would personally create my own constant rather than use `Intent.EXTRA_TEXT`. Is it possible that it is the `String` argument that is `null`? How to you retrieve the data? – PPartisan Aug 12 '15 at 08:56
  • @FrankN.Stein I'm creating the bundle which happens in the newInstance, a static method which returns the fragment after setting the arguments – shark1608 Aug 12 '15 at 08:56
  • @PPartisan No I double checked. The String `id` is never null before the arguments are set. It all seems to work if I just remove `setCotentView(..)` – shark1608 Aug 12 '15 at 08:58
  • @FrankN.Stein I'm following one of the recommended conventions. This way the data will be retained even if the fragment is re-created. – shark1608 Aug 12 '15 at 09:07
  • 1
    Ahh...your edit shows the problem. You're using a static fragment, but creating it dynamically! Remove the `` element in your `xml` and replace it with something like a `FrameLayout` to hold the Fragment instead. – PPartisan Aug 12 '15 at 09:34

4 Answers4

5

You have to pass the data to your fragment.

Create a static method on your fragment for instance creation. It should look like this:

public static newInstance(Object param) {
  DetailActivityFragment yourFragment = new DetailActivityFragment();
  Bundle args = new Bundle();
  args.put(key, value);
  yourFragment.setArguments(args);
  return yourFragment;
}

And in your onCreate method of the fragment you can get that data using the method "getArguments();

Your activity code is ok. But I would prefer using "replace" instead of "add" method.

Thomas R.
  • 7,988
  • 3
  • 30
  • 39
2

Your latest edit shows you are using a static fragment in your layout xml, but creating it dynamically. A static fragment is created in your xml file:

<fragment android:name="app.appone.DetailActivityFragment"
    android:id="@+id/fragment_detail"
    android:layout_weight="1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Whereas a dynamic fragment is generated in your code with FragmentManager. It makes sense that calling setContentView() would cause a conflict, as the fragment you are creating with FragmentManager is being replaced by the fragment you are defining in your xml file. The one in your xml, unlike your dynamic fragment, has no arguments, which is why it's returning null.

As you use android.R.id.content, you can remove this static fragment from your xml completely. Replace it with an empty layout, such as FrameLayout, and set an id attribute. Then, when using FragmentManager, replace android.R.id.content for this id.

For example:

<FrameLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/frag_container" />

And in your Activity file:

DetailActivityFragment frag = (DetailActivityFragment) getSupportFragmentManager().findFragmentById(R.id.frag_container);
if (frag == null) {
    frag = DetailActivityFragment.newInstance(id);
    getSupportFragmentManager()
        .beingTransaction()
        .add(R.id.frag_container, frag)
        .commit();
}
PPartisan
  • 8,173
  • 4
  • 29
  • 48
  • Excellent catch! I had completely overlooked Framelayout. I just tested with the changes and works perfectly. It also gave me the excuse to read more about FrameLayouts. Thanks! – shark1608 Aug 12 '15 at 09:46
  • @shark1608 You're welcome! FWIW, I'd recommend looking into the difference between static and dynamic fragments as well. I (and I believe most people) only ever use dynamic fragments because they are much more flexible, which could be why this solution might not be so obvious. – PPartisan Aug 12 '15 at 09:50
  • @shark1608 I'm not sure what you mean. Where are you trying to use `findViewbyId()` and for what purpose? – PPartisan Aug 12 '15 at 10:11
  • More or less what I posted :) – Thomas R. Aug 12 '15 at 10:16
  • My suggestion was to get rid of the in the layout file and use a placeholder instead. Therefore I do not need the findById method :) – Thomas R. Aug 12 '15 at 10:25
  • @ThomasR. Yes your answer was similar to what PPartisan suggested. I only accepted his answer because he also answered my original question about why setContentView was causing a problem. I upvoted your answer and definitely give credit to you as well! – shark1608 Aug 12 '15 at 16:41
  • That's all fine for me :) – Thomas R. Aug 12 '15 at 18:18
1

Thanks for your edit. I think you are using the wrong id for fragment replacement.

As in a previous comment you should first set the content view. Your layout file should have a placeholder view, e.g. Framelayout. Give your layout an id and reference this id in your replacement code.

Your "R.layout.activity_detail" should have a layout snippet like this:

<FrameLayout id="+@id/my_detail_frag"/>

And your activity code should look like this:

getSupportFragmentManager().beginTransaction().add(R.id.my_detail_frag,detailFrag).commit();
Thomas R.
  • 7,988
  • 3
  • 30
  • 39
0

This answer will do the trick for you:

Best practice for instantiating a new Android Fragment

You should use setArguments() and getArguments() to pass the Bundle into the Fragment.

Good luck!

Community
  • 1
  • 1
Or Polaczek
  • 126
  • 4
  • I have done exactly that. I've created the `newInstance` method in my fragment where I performed `setArguments()` . The `getArguments()` was done performed inside the OnCreate of the fragment – shark1608 Aug 12 '15 at 08:49
  • Hi, You wrote that you perform getParameters ('the fragment (activity_detail) if I perform getParameters()') Can you paste the code from inside the onCreate? – Or Polaczek Aug 12 '15 at 08:56